<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="keywords" content="imlgw,半岛铁盒,blog,Java博客,程序员,个人博客,java開發,程序員,個人博客,Java">
    <meta name="description" content="大悲无泪，大悟无言，大笑无声。">
    <meta name="author" content="Resolmi">
    
    <title>
        
            Java多线程基础 |
        
        Tadow
    </title>
    
<link rel="stylesheet" href="/css/style.css">

    <link rel="shortcut icon" href="https://static.imlgw.top/blog/20210731/BtJz541CcmJU.ico">
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/css/font-awesome.min.css">
    <script id="hexo-configurations">
    let KEEP = window.KEEP || {};
    KEEP.hexo_config = {"hostname":"imlgw.top","root":"/","language":"zh-CN","path":"search.json"};
    KEEP.theme_config = {"toc":{"enable":true,"number":true,"expand_all":true,"init_open":true},"style":{"primary_color":"#0066CC","avatar":"https://static.imlgw.top/blog/20210731/3C7hCSRR3lfq.png","favicon":"https://static.imlgw.top/blog/20210731/BtJz541CcmJU.ico","article_img_align":"left","left_side_width":"260px","content_max_width":"920px","hover":{"shadow":false,"scale":true},"first_screen":{"enable":true,"background_img":"/images/image.svg","description":"Keep It Simple & Stupid."},"scroll":{"progress_bar":{"enable":true},"percent":{"enable":true}}},"local_search":{"enable":true,"preload":false},"code_copy":{"enable":true,"style":"default"},"pjax":{"enable":true},"lazyload":{"enable":true},"version":"3.4.3"};
    KEEP.language_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 月前","year":"%s 年前"};
  </script>
<meta name="generator" content="Hexo 5.4.0"><link rel="stylesheet" href="/css/prism.css" type="text/css"></head>


<body>
<div class="progress-bar-container">
    
        <span class="scroll-progress-bar"></span>
    

    
        <span class="pjax-progress-bar"></span>
        <span class="pjax-progress-icon">
            <i class="fas fa-circle-notch fa-spin"></i>
        </span>
    
</div>


<main class="page-container">

    

    <div class="page-main-content">

        <div class="page-main-content-top">
            <header class="header-wrapper">

    <div class="header-content">
        <div class="left">
            
            <a class="logo-title" href="/">
                Tadow
            </a>
        </div>

        <div class="right">
            <div class="pc">
                <ul class="menu-list">
                    
                        <li class="menu-item">
                            <a class=""
                               href="/"
                            >
                                首页
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/archives"
                            >
                                归档
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/categories"
                            >
                                分类
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/sbe"
                            >
                                订阅
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/links"
                            >
                                友链
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/about"
                            >
                                关于
                            </a>
                        </li>
                    
                    
                        <li class="menu-item search search-popup-trigger">
                            <i class="fas fa-search"></i>
                        </li>
                    
                </ul>
            </div>
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fas fa-search"></i></div>
                
                <div class="icon-item menu-bar">
                    <div class="menu-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="header-drawer">
        <ul class="drawer-menu-list">
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/">首页</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/archives">归档</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/categories">分类</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/sbe">订阅</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/links">友链</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/about">关于</a>
                </li>
            
        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="page-main-content-middle">

            <div class="main-content">

                
                    <div class="fade-in-down-animation">
    <div class="article-content-container">

        <div class="article-title">
            <span class="title-hover-animation">Java多线程基础</span>
        </div>

        
            <div class="article-header">
                <div class="avatar">
                    <img src="https://static.imlgw.top/blog/20210731/3C7hCSRR3lfq.png">
                </div>
                <div class="info">
                    <div class="author">
                        <span class="name">Resolmi</span>
                        
                            <span class="author-label">BOSS</span>
                        
                    </div>
                    <div class="meta-info">
                        <div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fas fa-edit"></i>&nbsp;2019-04-07 00:00:00
    </span>
    
        <span class="article-categories article-meta-item">
            <i class="fas fa-folder"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/categories/%E5%B9%B6%E5%8F%91/">并发</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fas fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/">多线程</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/">并发编程</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
        <span class="article-wordcount article-meta-item">
            <i class="fas fa-file-word"></i>&nbsp;<span>16.3k 字</span>
        </span>
    
    
        <span class="article-min2read article-meta-item">
            <i class="fas fa-clock"></i>&nbsp;<span>74 分钟</span>
        </span>
    
    
        <span class="article-pv article-meta-item">
            <i class="fas fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

                    </div>
                </div>
            </div>
        

        <div class="article-content markdown-body">
            <h2 id="1-线程与进程区别"><a href="#1-线程与进程区别" class="headerlink" title="1.线程与进程区别"></a>1.线程与进程区别</h2><p>每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。线程是一组指令的集合，或者是程序的特殊段，它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程，它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。</p>
<p>使用线程可以把占据时间长的程序中的任务放到后台去处理，程序的运行速度可能加快，在一些等待的任务实现上如用户输入、文件读写和网络收发数据等，线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。</p>
<p>如果有大量的线程,会影响性能，因为操作系统需要在它们之间切换，更多的线程需要更多的内存空间，线程的中止需要考虑其对程序运行的影响。通常块模型数据是在多个线程间共享的，需要防止线程死锁情况的发生。</p>
<p>总结:进程是所有线程的集合，每一个线程是进程中的一条执行路径。</p>
<h2 id="2-为什么要使用多线程？多线程应用场景？"><a href="#2-为什么要使用多线程？多线程应用场景？" class="headerlink" title="2.为什么要使用多线程？多线程应用场景？"></a>2.为什么要使用多线程？多线程应用场景？</h2><p>答:主要能体现到多线程提高程序效率。</p>
<p>举例: 迅雷多线程下载、数据库连接池、分批发送短信等。</p>
<h2 id="3-线程创建方式"><a href="#3-线程创建方式" class="headerlink" title="3.线程创建方式"></a>3.线程创建方式</h2><h3 id="继承Thread类重写run方法"><a href="#继承Thread类重写run方法" class="headerlink" title="继承Thread类重写run方法"></a>继承Thread类重写run方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PlayGame</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot;PlayGame&quot;</span> + (i + <span class="number">1</span>));</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//void say() &#123;&#125;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ListenMusic</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot;ListenMusic&quot;</span> + (i + <span class="number">1</span>));<span class="comment">//底层操作居然是用的StringBuilder</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadDemo</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span></span><br><span class="line"><span class="function">	</span>&#123;</span><br><span class="line">		Thread music = <span class="keyword">new</span> ListenMusic();</span><br><span class="line">		Thread pg = <span class="keyword">new</span> PlayGame();</span><br><span class="line">		music.start(); <span class="comment">//三个线程同时运行抢占资源</span></span><br><span class="line">		<span class="keyword">try</span> &#123;</span><br><span class="line">			pg.start();</span><br><span class="line">			<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++) &#123;</span><br><span class="line">				System.out.println(<span class="string">&quot;    main方法:&quot;</span> + (i + <span class="number">1</span>));</span><br><span class="line">			&#125;</span><br><span class="line">			pg.start();</span><br><span class="line">		&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot;出现了IllegalThreadStateException异常&quot;</span>);	  <span class="comment">//线程只能启动一次</span></span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>这种方法官方也不推荐使用因为Java是单继承的继承了Thread类之后就不能继承其他的类</p>
<h3 id="实现Runnable接口"><a href="#实现Runnable接口" class="headerlink" title="实现Runnable接口"></a>实现Runnable接口</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CreateRunnable</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">for</span> (inti = <span class="number">0</span>; i&lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">			System.out.println(<span class="string">&quot;i:&quot;</span> + i);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadDemo2</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		System.out.println(<span class="string">&quot;-----多线程创建开始-----&quot;</span>);</span><br><span class="line">		<span class="comment">// 1.创建一个线程</span></span><br><span class="line">		CreateRunnable createThread = <span class="keyword">new</span> CreateRunnable();</span><br><span class="line">		<span class="comment">// 2.开始执行线程 注意 开启线程不是调用run方法，而是start方法</span></span><br><span class="line">		System.out.println(<span class="string">&quot;-----多线程创建启动-----&quot;</span>);</span><br><span class="line">		Thread thread = <span class="keyword">new</span> Thread(createThread);</span><br><span class="line">		thread.start();</span><br><span class="line">		System.out.println(<span class="string">&quot;-----多线程创建结束-----&quot;</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="匿名内部类"><a href="#匿名内部类" class="headerlink" title="匿名内部类"></a>匿名内部类</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InClass</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		 Thread thread = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">				<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">					<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i&lt; <span class="number">100</span>; i++) &#123;</span><br><span class="line">						System.out.println(<span class="string">&quot;i:&quot;</span> + i);</span><br><span class="line">					&#125;</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;);</span><br><span class="line">		thread.start();</span><br><span class="line"></span><br><span class="line">		 <span class="comment">//lambda表达式还是比较简洁</span></span><br><span class="line">		 <span class="keyword">new</span> Thread(()-&gt; &#123;<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt;<span class="number">100</span>; i++) &#123;System.out.println(<span class="string">&quot;lambda:&quot;</span> +i);&#125;&#125;).start();</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>线程创建方式不只这些还有很多，后面再介绍</p>
<h3 id="Thread-类中的start-和-run-方法有什么区别？"><a href="#Thread-类中的start-和-run-方法有什么区别？" class="headerlink" title="Thread 类中的start() 和 run() 方法有什么区别？"></a>Thread 类中的start() 和 run() 方法有什么区别？</h3><p>这个问题经常被问到，但还是能从此区分出面试者对Java线程模型的理解程度。<code>start()</code>方法被用来启动新创建的线程，而且<code>start()</code>内部native方法<code>start0()</code>调用了run()方法，这和直接调用<code>run()</code>方法的效果不一样。当你调用<code>run()</code>方法的时候，只会是在原来的线程中调用，没有新的线程启动，<code>start()</code>方法才会启动新线程</p>
<h2 id="4-Thread构造函数"><a href="#4-Thread构造函数" class="headerlink" title="4.Thread构造函数"></a>4.Thread构造函数</h2><table>
<thead>
<tr>
<th align="left"><strong>常用线程api方法</strong></th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td align="left">start()</td>
<td>启动线程</td>
</tr>
<tr>
<td align="left">currentThread()</td>
<td>获取当前线程对象</td>
</tr>
<tr>
<td align="left">getID()</td>
<td>获取当前线程ID   Thread-编号 该编号从0开始</td>
</tr>
<tr>
<td align="left">getName()</td>
<td>获取当前线程名称</td>
</tr>
<tr>
<td align="left">sleep(long mill)</td>
<td>休眠线程</td>
</tr>
<tr>
<td align="left">Stop（）</td>
<td>停止线程,</td>
</tr>
<tr>
<td align="left"><strong>常用线程构造函数</strong></td>
<td></td>
</tr>
<tr>
<td align="left">Thread（）</td>
<td>分配一个新的 Thread 对象</td>
</tr>
<tr>
<td align="left">Thread（String name）</td>
<td>分配一个新的 Thread对象，具有指定的 name正如其名。</td>
</tr>
<tr>
<td align="left">Thread（Runnable r）</td>
<td>分配一个新的 Thread对象</td>
</tr>
<tr>
<td align="left">Thread（Runable r, String name）</td>
<td>分配一个新的 Thread对象，具有指定的 name正如其名。</td>
</tr>
<tr>
<td align="left">Thread(ThreadGroup group, Runnable target)</td>
<td>分配一个新的 Thread对象，如果不传<code>ThreadGroup</code>默认加入当前线程的<code>ThreadGroup</code>中</td>
</tr>
<tr>
<td align="left">Thread(ThreadGroup group, Runnable target, String name)</td>
<td>分配一个新的 <code>Thread</code>对象，使其具有  <code>target</code>作为其运行对象，具有指定的 <code>name</code>作为其名称，属于  <code>group</code>引用的线程组。</td>
</tr>
<tr>
<td align="left">Thread(ThreadGroup group, Runnable target, String name,  long stackSize)</td>
<td>分配一个新的 <code>Thread</code>对象，以便它具有  <code>target</code>作为其运行对象，将指定的 <code>name</code>正如其名，以及属于该线程组由称作  <code>group</code> ，并具有指定的 <em>堆栈大小</em></td>
</tr>
</tbody></table>
<h3 id="Thread构造方法的一些细节"><a href="#Thread构造方法的一些细节" class="headerlink" title="Thread构造方法的一些细节"></a>Thread构造方法的一些细节</h3><p>直接上源码</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">(ThreadGroup g, Runnable target, String name,</span></span></span><br><span class="line"><span class="params"><span class="function">                  <span class="keyword">long</span> stackSize, AccessControlContext acc,</span></span></span><br><span class="line"><span class="params"><span class="function">                  <span class="keyword">boolean</span> inheritThreadLocals)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (name == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException(<span class="string">&quot;name cannot be null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.name = name;</span><br><span class="line"></span><br><span class="line">    Thread parent = currentThread();</span><br><span class="line">    SecurityManager security = System.getSecurityManager();</span><br><span class="line">    <span class="keyword">if</span> (g == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">/* Determine if it&#x27;s an applet or not */</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* If there is a security manager, ask the security manager</span></span><br><span class="line"><span class="comment">               what to do. */</span></span><br><span class="line">        <span class="keyword">if</span> (security != <span class="keyword">null</span>) &#123;</span><br><span class="line">            g = security.getThreadGroup();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* If the security doesn&#x27;t have a strong opinion of the matter</span></span><br><span class="line"><span class="comment">               use the parent thread group. */</span></span><br><span class="line">        <span class="keyword">if</span> (g == <span class="keyword">null</span>) &#123;</span><br><span class="line">            g = parent.getThreadGroup();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* checkAccess regardless of whether or not threadgroup is</span></span><br><span class="line"><span class="comment">           explicitly passed in. */</span></span><br><span class="line">    g.checkAccess();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * Do we have the required permissions?</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">    <span class="keyword">if</span> (security != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (isCCLOverridden(getClass())) &#123;</span><br><span class="line">            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    g.addUnstarted();</span><br><span class="line">    <span class="keyword">this</span>.group = g;</span><br><span class="line">    <span class="comment">//这里继承了父类的一些属性</span></span><br><span class="line">    <span class="keyword">this</span>.daemon = parent.isDaemon();</span><br><span class="line">    <span class="keyword">this</span>.priority = parent.getPriority();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (security == <span class="keyword">null</span> || isCCLOverridden(parent.getClass()))</span><br><span class="line">        <span class="keyword">this</span>.contextClassLoader = parent.getContextClassLoader();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="keyword">this</span>.contextClassLoader = parent.contextClassLoader;</span><br><span class="line">    <span class="keyword">this</span>.inheritedAccessControlContext =</span><br><span class="line">        acc != <span class="keyword">null</span> ? acc : AccessController.getContext();</span><br><span class="line">    <span class="comment">//传入的Runnable接口</span></span><br><span class="line">    <span class="keyword">this</span>.target = target;</span><br><span class="line">    setPriority(priority);</span><br><span class="line">    <span class="keyword">if</span> (inheritThreadLocals &amp;&amp; parent.inheritableThreadLocals != <span class="keyword">null</span>)</span><br><span class="line">        <span class="keyword">this</span>.inheritableThreadLocals =</span><br><span class="line">        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);</span><br><span class="line">    <span class="comment">/* Stash the specified stack size in case the VM cares */</span></span><br><span class="line">    <span class="keyword">this</span>.stackSize = stackSize;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Set thread ID */</span></span><br><span class="line">    tid = nextThreadID();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>① 创建的线程会继承父线程的一些属性，是否是守护线程 ，和优先级。</p>
<p>②使用Thread(Runnable r)创建线程时<code>this.target = target</code>传入的<code>Runnable</code>接口在这里赋值然后会在<code>run方法</code>中被调用。</p>
<p>③<code>stacksize</code>这个参数会影响<code>虚拟机栈</code>的大小，这个值越大能存放的<code>栈帧</code>就越多，可达到的递归深度越深，但是这个参数不一定有效，有的平台可能并没有效果，具体的<code>JVM</code>底层的知识等后面学到再来细化</p>
<p>④一种奇怪的写法，这里只会执行重写<code>Thread</code>的<code>run</code>方法，这里从源码上可以看出来，传递<code>Runnable</code>接口其实是在Thread的run方法中调用了<code>target</code>的<code>run</code>方法，如果同时再<code>继承</code>Thread类，重写<code>run</code>方法，调用的就不再是Thread类的run方法，而是匿名Thread子类重写的run方法</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Thread t = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;Runnable&quot;</span>);</span><br><span class="line">&#125;) &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Thread&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>④线程<code>tid</code>通过<code>threadSeqNumber</code>从0自增的来，main线程是第<code>10</code>个线程因为会有一些守护线程会在main启动前启动.</p>
<h2 id="5-守护线程"><a href="#5-守护线程" class="headerlink" title="5.守护线程"></a>5.守护线程</h2><p>Java中有两种线程，一种是用户线程，另一种是守护线程。</p>
<p>用户线程是指用户自定义创建的线程，主线程停止，用户线程不会停止</p>
<ul>
<li>守护线程顾名思义当父线程结束时，守护线程也会被停止。</li>
<li>JVM只有在最后一个非守护线程结束后才会退出</li>
<li>在线程start前<code>setDaemon(true)</code>方法设置为守护线程，否则就会报错</li>
<li>父线程是守护线程，子线程默认是守护线程。</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Daemon</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">500</span>;i++) &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName()+i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DaemonDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[]args)</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getPriority());</span><br><span class="line">        Thread r1=<span class="keyword">new</span> Thread(<span class="keyword">new</span> Daemon(),<span class="string">&quot;后台线程&quot;</span>);     <span class="comment">//设置该线程为后台线程</span></span><br><span class="line">        r1.setDaemon(<span class="keyword">true</span>);                        <span class="comment">//前台线程挂掉后，后台线程就会挂掉</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">50</span>;i++) &#123;                   </span><br><span class="line">            System.out.println(<span class="string">&quot;main&quot;</span>+i);</span><br><span class="line">            <span class="keyword">if</span>(i==<span class="number">10</span>) &#123;</span><br><span class="line">                r1.start();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;主线程执行完毕&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><p><code>心跳检测</code>，在通信过程中会需要判断对方是否在线，会需要创建一条线程去做这些事情，但是如果这样会导致<code>主线程停止工作</code>了，但是检测心跳的线程仍然在继续工作，JVM就无法停下来，显然这样时不合理的，这时就可以把检测心跳的线程设置为<code>守护线程</code>，这样当它主线程停止工作时它的守护线程也会随之停止。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//心跳检测MOCK</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            Thread inThread = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;start heart check&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        Thread.sleep(<span class="number">1_00</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="comment">//将子线程设置为守护线程</span></span><br><span class="line">            inThread.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">            inThread.start();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1_000</span>);</span><br><span class="line">                System.err.println(<span class="string">&quot;Thread finish done...&quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t.start();</span><br><span class="line">        <span class="comment">//主线程(main)--&gt;t--&gt;inThread</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="6-线程的状态"><a href="#6-线程的状态" class="headerlink" title="6.线程的状态"></a>6.线程的状态</h2><p>线程从创建、运行到结束总是处于下面五个状态之一：新建状态、就绪状态、运行状态、阻塞状态及死亡状态。</p>
<p><img  
                     lazyload
                     src="/images/loading.svg"
                     data-src="http://static.imlgw.top///20181226/WXPYz3SiidMT.png?imageslim"
                      alt="mark"
                ></p>
<ul>
<li><p>新建状态<br>当用new操作符创建一个线程时， 例如new Thread(r)，线程还没有开始运行，此时线程处在新建状态。 当一个线程处于新生状态时，程序还没有开始运行线程中的代码</p>
</li>
<li><p>就绪状态<br>一个新创建的线程并不自动开始运行，要执行线程，必须调用线程的start()方法。当线程对象调用start()方法即启动了线程，start()方法创建线程运行的系统资源，并调度线程运行run()方法。当start()方法返回后，线程就处于就绪状态。<br>处于就绪状态的线程并不一定立即运行run()方法，线程还必须同其他线程竞争CPU时间，只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中，不可能同时运行多个线程，一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由<code>Java</code>运行时系统的线程调度程序(<em>thread scheduler</em>)来调度的。</p>
</li>
<li><p>运行状态<br>当线程获得CPU时间后，它才进入运行状态，真正开始执行run()方法.</p>
</li>
<li><p>阻塞状态<br>线程运行过程中，可能由于各种原因进入阻塞状态:<br>1&gt;线程通过调用sleep方法进入睡眠状态；<br>2&gt;线程调用一个在I/O上被阻塞的操作，即该操作在输入输出操作完成之前不会返回到它的调用者；<br>3&gt;线程试图得到一个锁，而该锁正被其他线程持有；<br>4&gt;线程在等待某个触发条件；</p>
</li>
<li><p>死亡状态</p>
<p>有两个原因会导致线程死亡：</p>
<ol>
<li><p>run方法正常退出而自然死亡，</p>
</li>
<li><p>一个未捕获的异常终止了run方法而使线程猝死。 为了确定线程在当前是否存活着（就是要么是可运行的，要么是被阻塞了），需要使用<code>isAlive</code>方法。如果是可运行或被阻塞，这个方法返回true； 如果线程仍旧是new状态且不是可运行的， 或者线程死亡了，则返回false.</p>
</li>
</ol>
</li>
</ul>
<h2 id="7-join-方法"><a href="#7-join-方法" class="headerlink" title="7.join()方法"></a>7.join()方法</h2><h3 id="源码解析"><a href="#源码解析" class="headerlink" title="源码解析"></a>源码解析</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">join</span><span class="params">(<span class="keyword">long</span> millis)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">       <span class="keyword">long</span> base = System.currentTimeMillis();</span><br><span class="line">       <span class="keyword">long</span> now = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">if</span> (millis &lt; <span class="number">0</span>) &#123;</span><br><span class="line">           <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;timeout value is negative&quot;</span>);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">if</span> (millis == <span class="number">0</span>) &#123;</span><br><span class="line">           <span class="keyword">while</span> (isAlive()) &#123;</span><br><span class="line">               wait(<span class="number">0</span>);</span><br><span class="line">           &#125;</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="keyword">while</span> (isAlive()) &#123;</span><br><span class="line">               <span class="keyword">long</span> delay = millis - now;</span><br><span class="line">               <span class="keyword">if</span> (delay &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">                   <span class="keyword">break</span>;</span><br><span class="line">               &#125;</span><br><span class="line">               wait(delay);</span><br><span class="line">               now = System.currentTimeMillis() - base;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>①<code>thread.join()</code>没有参数会默认调用<code>join(0)</code>然后回轮询检查调用<code>join()</code>的线程也就是是<code>thread</code>线程是否<code>isAlive()</code>如果thread依然存活就回释放<code>当前线程</code>的CPU执行权，然后继续轮询，知道<code>thread</code>进入终止状态。</p>
<p>②<code>join(long millis)</code> 参数的作用就是当前线程最多等待时间，限时等待，避免无止境的等待。</p>
<p>③一个线程自己调用自己的<code>join</code>方法该线程就回一直<code>wait</code>下去因为他自己要一直等自己😄</p>
<h3 id="应用场景-1"><a href="#应用场景-1" class="headerlink" title="应用场景"></a>应用场景</h3><blockquote>
<p> 多线程同时采集数据，最后将统计的总时间等信息存到数据库中，如果不jion就无法统一结束的时间</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadJoin3</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> l1 = System.currentTimeMillis();</span><br><span class="line">        Thread t0 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> CaptureMachine(<span class="string">&quot;M0&quot;</span>, <span class="number">1000</span>));</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> CaptureMachine(<span class="string">&quot;M1&quot;</span>, <span class="number">2000</span>));</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> CaptureMachine(<span class="string">&quot;M2&quot;</span>, <span class="number">4000</span>));</span><br><span class="line">        t0.start();</span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">        <span class="comment">//让主线程等待子线程结束然后统计最后总体结束的时间</span></span><br><span class="line">        t0.join();</span><br><span class="line">        t1.join();</span><br><span class="line">        t2.join();</span><br><span class="line">        <span class="keyword">long</span> l = System.currentTimeMillis();</span><br><span class="line">        System.out.println(<span class="string">&quot;end save begin timestamp:&quot;</span> + l1 + <span class="string">&quot;end timestamp&quot;</span> + l);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CaptureMachine</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String machineId;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">long</span> spentTime;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">CaptureMachine</span><span class="params">(String machineId, <span class="keyword">long</span> spentTime)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.machineId = machineId;</span><br><span class="line">        <span class="keyword">this</span>.spentTime = spentTime;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(spentTime);</span><br><span class="line">            System.out.println(machineId + <span class="string">&quot; capture done&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="8-优先级"><a href="#8-优先级" class="headerlink" title="8.优先级"></a>8.优先级</h2><p>现代操作系统基本采用时分的形式调度运行的线程，线程分配得到的时间片的多少决定了线程使用处理器资源的多少，也对应了线程优先级这个概念。在JAVA线程中，通过一个int priority来控制优先级，范围为1-10，其中10最高，默认值为5。下面是Demo（基于1.8）中关于priority的一些量和方法。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadSimpleAPI2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Thread t0 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++) &#123;</span><br><span class="line">                Optional.of(Thread.currentThread().getName() + <span class="string">&quot;-index&quot;</span> + i).ifPresent(System.out::println);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t0.setPriority(Thread.MAX_PRIORITY);</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++) &#123;</span><br><span class="line">                Optional.of(Thread.currentThread().getName() + <span class="string">&quot;-index&quot;</span> + i).ifPresent(System.out::println);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t1.setPriority(Thread.NORM_PRIORITY);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++) &#123;</span><br><span class="line">                Optional.of(Thread.currentThread().getName() + <span class="string">&quot;-index&quot;</span> + i).ifPresent(System.out::println);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t2.setPriority(Thread.MIN_PRIORITY);</span><br><span class="line">        t0.start();</span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="9-Interrupt方法"><a href="#9-Interrupt方法" class="headerlink" title="9.Interrupt方法"></a>9.Interrupt方法</h2><h3 id="看看源码"><a href="#看看源码" class="headerlink" title="看看源码"></a>看看源码</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">interrupt</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span> != Thread.currentThread())</span><br><span class="line">            checkAccess();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">synchronized</span> (blockerLock) &#123;</span><br><span class="line">            Interruptible b = blocker;</span><br><span class="line">            <span class="keyword">if</span> (b != <span class="keyword">null</span>) &#123;</span><br><span class="line">                interrupt0();           <span class="comment">// Just to set the interrupt flag</span></span><br><span class="line">                b.interrupt(<span class="keyword">this</span>);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        interrupt0();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在知乎上看见一个好的回答：首先，一个线程不应该由其他线程来强制中断或停止，而是应该由线程自己<code>自行停止</code>。所以，<code>Thread.stop()</code> ,<code>Thread.suspend()</code>,<code>Thread.resume()</code>都已经被废弃了。而<code>Thread.interrupt()</code>的作用也不是中断线程，<em>而是通知线程该结束了</em> 具体中断还是继续运行还是由被通知的线程自己处理。具体来说，当对一个线程调用<code>interrupt()</code>时</p>
<p>①如果线程处于阻塞状态(sleep,wait,join等)，那么线程将<del>立即退出被阻塞状态</del>并抛出一个异常(2019.8.10 fix)</p>
<blockquote>
<p>这里其实是有点问题的，在有同步锁存在的情况下，并不一定会立即退出被阻塞的状态，即使抛出异常也要等到再次拿到锁之后才能抛出，同时也不是所有的阻塞操作都会响应中断信号，比如IO操作之类的都不会响应中断信号</p>
</blockquote>
<p><strong>验证Demo</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WaitNotify</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        Object object = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">        Thread thread1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程1 获取到监视器锁&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        object.wait();</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 恢复啦。我为什么这么久才恢复，因为notify方法虽然早就发生了，可是我还要获取锁才能继续执行。&quot;</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 wait方法抛出了InterruptedException异常，即使是异常，我也是要获取到监视器锁了才会抛出&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程1&quot;</span>);</span><br><span class="line">        thread1.start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程2 拿到了监视器锁。为什么呢，因为线程1 在 wait 方法的时候会自动释放锁&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程2 设置线程1 中断&quot;</span>);</span><br><span class="line">                    thread1.interrupt();</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程2 执行完了 中断，先休息3秒再说。&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程2 休息完啦。注意了，调sleep方法和wait方法不一样，不会释放监视器锁&quot;</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line"></span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程2 休息够了，结束操作&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程2&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>②如果线程处于正常活动状态，那么会将该线程的<code>中断标志位</code>设置为true，仅此而已，被设置中断标志的线程将继续正常运行，不受影响。</p>
<p>③对已经结束的线程调用<code>interupt</code>没有任何效果</p>
<p>上面只是简单的分析，其实情况还是很复杂的，后面再来总结</p>
<p><strong>具体的小案例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadInterrup2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Thread main=Thread.currentThread();</span><br><span class="line"></span><br><span class="line">        Thread t=<span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t.start();</span><br><span class="line">	</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//t.interrupt(); 这里打断的是t线程但是阻塞的是main线程所以打断不了，捕获不到异常</span></span><br><span class="line">            main.interrupt();</span><br><span class="line">            System.out.println(<span class="string">&quot;打断 main 线程&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        t2.start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//这里阻塞的是main线程</span></span><br><span class="line">            t.join();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>看懂这个小案例应该就理解interrupt了。</p>
<h3 id="如何优雅的结束线程"><a href="#如何优雅的结束线程" class="headerlink" title="如何优雅的结束线程"></a>如何优雅的结束线程</h3><p><strong>1. 使用“开关”</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadCloseGraceful</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Worker worker=<span class="keyword">new</span> Worker();</span><br><span class="line">        worker.start();</span><br><span class="line">        Thread.sleep(<span class="number">10000</span>); <span class="comment">//等待10s</span></span><br><span class="line">        worker.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Worker</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">    <span class="comment">//优雅的停止线程-----开关</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> start = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (start)&#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shutdown</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.start=<span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>为了及时的感知到开关的变化 start需要声明为 volatile（后面讲Volatile的时候会说到）</p>
</blockquote>
<p><strong>2. 轮询中断标志位</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadCloseGraceful2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Worker2 worker2 = <span class="keyword">new</span> Worker2();</span><br><span class="line">        worker2.start();</span><br><span class="line">        Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">        worker2.interrupt();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Worker2</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">    <span class="comment">//优雅的停止线程2-----打断</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line">            <span class="comment">/*try &#123;</span></span><br><span class="line"><span class="comment">                Thread.sleep(1);</span></span><br><span class="line"><span class="comment">            &#125; catch (InterruptedException e) &#123;</span></span><br><span class="line"><span class="comment">                e.printStackTrace();</span></span><br><span class="line"><span class="comment">                break; //return 会直接退出</span></span><br><span class="line"><span class="comment">            &#125;*/</span></span><br><span class="line">            <span class="comment">//代码有可能在执行isInterrupted之前就Block了</span></span><br><span class="line">            <span class="keyword">if</span>(isInterrupted())&#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//-----------</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>3. 利用守护线程</strong></p>
<p>上面的代码已经提到了，有可能在轮询<code>开关</code> 或者 轮询<code>中断标志位</code>之前就堵塞了，这时也不能一直等该下去所以就需要强制结束线程的方法，<code>（当然不会是stop）</code> 这里就可以利用守护线程的特性去完成这件事</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadService</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span>  Thread executeThread;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span>  <span class="keyword">volatile</span>  <span class="keyword">boolean</span> finished=<span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(Runnable task)</span></span>&#123;</span><br><span class="line">        executeThread =<span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            <span class="comment">//子线程</span></span><br><span class="line">            Thread t=<span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">                task.run();</span><br><span class="line">            &#125;);</span><br><span class="line">            t.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">            t.start();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                t.join(); <span class="comment">//这里阻塞的是executeThread</span></span><br><span class="line">                finished=<span class="keyword">true</span>;</span><br><span class="line">                <span class="comment">//到这里说明executeThread已经不阻塞了,子线程已经执行完了，没有超时</span></span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">                System.out.println(<span class="string">&quot;TLE，executeThread execution was interrupted&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        executeThread.start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shutdown</span><span class="params">(<span class="keyword">long</span> mills)</span></span>&#123;</span><br><span class="line">        <span class="keyword">long</span> base=System.currentTimeMillis();</span><br><span class="line">        <span class="keyword">while</span> (!finished)&#123; <span class="comment">//轮询检查标志位，看是否已经结束</span></span><br><span class="line">            <span class="keyword">if</span>(System.currentTimeMillis()-base&gt;=mills)&#123;</span><br><span class="line">                <span class="comment">//超时了没有完成</span></span><br><span class="line">                System.out.println(<span class="string">&quot;TLE, will end it now&quot;</span>);</span><br><span class="line">                executeThread.interrupt(); <span class="comment">//打断executeThread</span></span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//没超时</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                executeThread.sleep(<span class="number">10</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">                System.out.println(<span class="string">&quot;executeThread was interrupted when shutdown&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//标志位复原</span></span><br><span class="line">        finished=<span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>将待执行的<code>task</code>传递到<code>ThreadService</code>中然后会创建一个<code>executeThread</code>的线程，在线程中创建一个子线程去执行<code>task</code>的<code>run</code>方法然后将子线程设置为<code>executeThread</code>的守护线程然后<code>join</code>阻塞<code>executeThread</code>线程，同时会调用<code>ThreadService</code>的<code>shutdown</code>方法传入一个最长等待时间然后<code>轮询标志位</code>检查是否结束，如果超时就会打断<code>executeThread</code>进而结束<code>executeThread</code>的子线程也就是<code>task</code></p>
<h3 id="Thread-interrupted"><a href="#Thread-interrupted" class="headerlink" title="Thread.interrupted()"></a>Thread.interrupted()</h3><p>这个方法和<code>isInterrupt()</code>类似但是他会清除中断标志位为<code>false</code>方便之后的中断操作而且这个是<code>静态方法</code>，所以你用线程实例去调用这个方法没有任何意义，它这里是用来判断<strong>当前执行线程</strong>是否 <code>interrupt</code> ，并且设置中断标志位为<code>false</code></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Tests whether the current thread has been interrupted.  The</span><br><span class="line"> * <span class="tag">&lt;<span class="name">i</span>&gt;</span>interrupted status<span class="tag">&lt;/<span class="name">i</span>&gt;</span> of the thread is cleared by this method.  In</span><br><span class="line"> * other words, if this method were to be called twice in succession, the</span><br><span class="line"> * second call would return false (unless the current thread were</span><br><span class="line"> * interrupted again, after the first call had cleared its interrupted</span><br><span class="line"> * status and before the second call had examined it).</span><br><span class="line"> *</span><br><span class="line"> * <span class="tag">&lt;<span class="name">p</span>&gt;</span>A thread interruption ignored because a thread was not alive</span><br><span class="line"> * at the time of the interrupt will be reflected by this method</span><br><span class="line"> * returning false.</span><br><span class="line"> *</span><br><span class="line"> * @return  <span class="tag">&lt;<span class="name">code</span>&gt;</span>true<span class="tag">&lt;/<span class="name">code</span>&gt;</span> if the current thread has been interrupted;</span><br><span class="line"> *          <span class="tag">&lt;<span class="name">code</span>&gt;</span>false<span class="tag">&lt;/<span class="name">code</span>&gt;</span> otherwise.</span><br><span class="line"> * @see #isInterrupted()</span><br><span class="line"> * @revised 6.0</span><br><span class="line"> */</span><br></pre></td></tr></table></figure>

<p>同时在抛出<code>InterruptedException</code> 之后中断状态也会被自动清除为false</p>
<blockquote>
<p>if any thread has interrupted the current thread. The <i>interrupted status</i> of the current thread is cleared when this exception is thrown.     —-Thread.sleep注释</p>
</blockquote>
<h2 id="10-Yield方法"><a href="#10-Yield方法" class="headerlink" title="10.Yield方法"></a>10.Yield方法</h2><p>Thread.yield()方法的作用：暂停当前正在执行的线程，并执行其他线程。（可能没有效果）<br>yield()让当前正在运行的线程回到可运行状态，以允许具有相同优先级的其他线程获得运行的机会。因此，使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是，实际中无法保证yield()达到让步的目的，因为，让步的线程可能被线程调度程序再次选中。<br>结论：大多数情况下，yield()将导致线程从运行状态转到可运行状态，但有可能没有效果。</p>
<h2 id="11-Synchronized关键字"><a href="#11-Synchronized关键字" class="headerlink" title="11.Synchronized关键字"></a>11.Synchronized关键字</h2><h3 id="线程安全问题"><a href="#线程安全问题" class="headerlink" title="线程安全问题"></a>线程安全问题</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TicketRunnable</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_NO = <span class="number">500</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> index = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (index &gt; MAX_NO) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">5</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;第：&quot;</span> + index++);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用这个创建多个<code>Thread</code>然后运行</p>
<blockquote>
<p>二号窗口第：497<br>三号窗口第：499<br>一号窗口第：498<br>一号窗口第：500<br>二号窗口第：<code>502</code><br>三号窗口第：<code>501</code></p>
</blockquote>
<p>可以看出打印出了501，502明显不对为什么会出现这种问题呢？其实仔细想想也很容易理解</p>
<p><img  
                     lazyload
                     src="/images/loading.svg"
                     data-src="http://static.imlgw.top///20190326/zSGNeiCW2zc1.png?imageslim"
                      alt="mark"
                ></p>
<p>当两个线程如图所示的情况，2号线程<code>index=500</code>然后<code>index++</code>然后 1号线程读取到<code>index</code>的值就会产生这个问题。</p>
<h3 id="同步代码块"><a href="#同步代码块" class="headerlink" title="同步代码块"></a>同步代码块</h3><p><strong>解决线程安全问题</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TicketRunnable</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_NO = <span class="number">500</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> index = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object MONITOR = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            <span class="keyword">synchronized</span> (MONITOR) &#123;</span><br><span class="line">                <span class="comment">//单线程</span></span><br><span class="line">                <span class="keyword">if</span> (index &gt; MAX_NO) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">5</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;第：&quot;</span> + index++);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>利用<code>MONITOR</code>对象作为同步锁同步之后的部分就相当于单线程，<code>MONITOR</code>锁对象一般设置为<code>final</code>的避免在执行过程中对<code>MONITOR</code>对象进行改变而产生无法预料的后果</p>
<h3 id="同步方法"><a href="#同步方法" class="headerlink" title="同步方法"></a>同步方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SynchronizeRunnable</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_NO = <span class="number">500</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> index = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//this锁</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (ticket()) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">boolean</span> <span class="title">ticket</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//synchronized (this) &#123;</span></span><br><span class="line">            <span class="comment">//1.getFiled</span></span><br><span class="line">            <span class="keyword">if</span> (index &gt; MAX_NO) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">5</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// getFiled index</span></span><br><span class="line">            <span class="comment">// index=index+1</span></span><br><span class="line">            <span class="comment">// putFiled index</span></span><br><span class="line">            <span class="comment">//同步代码块就是保护共享数据index, MAX_NO不是,他是只读数据</span></span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;第：&quot;</span> + index++);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">       <span class="comment">// &#125;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>默认加的是<code>this</code>锁</p>
<p><strong>证明this锁的存在</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SynchronizedThis</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ThisLock thisLock = <span class="keyword">new</span> ThisLock();</span><br><span class="line">        Thread thread = <span class="keyword">new</span> Thread(() -&gt; thisLock.m1(), <span class="string">&quot;Thread0&quot;</span>);</span><br><span class="line">        thread.start();</span><br><span class="line">        Thread thread1 = <span class="keyword">new</span> Thread(() -&gt; thisLock.m2(), <span class="string">&quot;Thread1&quot;</span>);</span><br><span class="line">        thread1.start();</span><br><span class="line">        Thread thread2 = <span class="keyword">new</span> Thread(() -&gt; thisLock.m3(), <span class="string">&quot;Thread2&quot;</span>);</span><br><span class="line">        thread2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ThisLock</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object LOCK = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">m3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName());</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行上面的代码会发现<code>Thread0</code>和<code>Thread2</code>会先打印出来因为他们不是同一个锁不用等待对方，而<code>Thread1</code>会等待一段时间后才会执行因为它需要等待<code>Thread0</code>释放锁而这个锁只能是<code>this锁</code></p>
<p><strong>证明class锁的存在</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SynchronizedClass</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Thread thread0 = <span class="keyword">new</span> Thread(() -&gt; ClassLock.m1(), <span class="string">&quot;Thread0&quot;</span>);</span><br><span class="line">        thread0.start();</span><br><span class="line">        Thread thread1 = <span class="keyword">new</span> Thread(() -&gt; ClassLock.m2(), <span class="string">&quot;Thread1&quot;</span>);</span><br><span class="line">        thread1.start();</span><br><span class="line">        Thread thread2 = <span class="keyword">new</span> Thread(() -&gt; ClassLock.m3(), <span class="string">&quot;Thread2&quot;</span>);</span><br><span class="line">        thread2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClassLock</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (ClassLock.class) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;static&quot;</span> + Thread.currentThread().getName());</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">m2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">m3</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">10_000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行上面的代码会发现最开始只有一个线程会去执行静态代码快，在静态代码快执行完之后<code>Thread2</code>会和另一个线程一起执行，说明一开始<code>Thread2</code>回和其中一个线程抢<code>Class锁</code>执行静态代码块（静态代码块只会执行一次）</p>
<h3 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h3><blockquote>
<p>一个线程可以持有多个锁，而这样就可能会导致<code>死锁</code>的产生</p>
</blockquote>
<p><strong>死锁示例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Service1</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span>  <span class="keyword">final</span> Object LOCK=<span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Service2 service2;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span> <span class="title">s1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;s1==============&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">s2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;s2==============&quot;</span>);</span><br><span class="line">            service2.m2();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setService2</span><span class="params">(Service2 service2)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.service2 = service2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">---------------------------------------------------</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Service2</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Service1 service1;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Service2</span><span class="params">(Service1 service1)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.service1 = service1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span>  <span class="keyword">final</span>  Object LOCK=<span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span>  <span class="title">m1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;m1&quot;</span>);</span><br><span class="line">            service1.s1();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span>  <span class="title">m2</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;m2&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">-------------------------------------------------</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadLockTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Service1 service1=<span class="keyword">new</span> Service1();</span><br><span class="line">        Service2 service2 =<span class="keyword">new</span> Service2(service1);</span><br><span class="line">        service1.setService2(service2);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line">                service2.m1();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line">                service1.s2();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>执行上面代码就会发现在运行一段时间后两个线程都<code>阻塞</code>了，这就是<code>死锁</code></p>
<ul>
<li><code>jps</code>&amp;<code>jstack</code>  分析死锁</li>
</ul>
<p><img  
                     lazyload
                     src="/images/loading.svg"
                     data-src="http://static.imlgw.top///20190328/BG9eU9Rq8ae0.png?imageslim"
                      alt="mark"
                ></p>
<p>两个线程都需要对方手上的的锁，陷入僵持状态，就会产生死锁，也可以使用<code>jconsole</code>图形化界面来分析</p>
<h2 id="12-线程间通讯"><a href="#12-线程间通讯" class="headerlink" title="12.线程间通讯"></a>12.线程间通讯</h2><p>在Java平台中，Object.wait()/notify() 等方法可用于实现线程的等待和通知，wait将当前线程暂停生命周期变为 <strong>WAITING</strong> ，而notify() 则可以唤醒一个被暂停的线程从而实现通知，一般来说wait() 代码模板类似下面</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(someObj)&#123;</span><br><span class="line">    <span class="keyword">while</span>(保护条件不成立)&#123;</span><br><span class="line">        <span class="comment">//等待</span></span><br><span class="line">        someObj.wait();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//保护条件满足</span></span><br><span class="line">    doAction();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>而<code>notify()</code> 对应代码模板如下</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(someObj)&#123;</span><br><span class="line">    <span class="comment">//更新等待线程的保护条件设计的共享变量</span></span><br><span class="line">    updateSharedDate();</span><br><span class="line">    <span class="comment">//唤醒其他线程</span></span><br><span class="line">    someObj,notify();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="生产者消费者模型"><a href="#生产者消费者模型" class="headerlink" title="生产者消费者模型"></a>生产者消费者模型</h3><p><strong>错误示例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProduceConsumerVersion1</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ProduceConsumerVersion1 pc = <span class="keyword">new</span> ProduceConsumerVersion1();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                pc.produce();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;Produce&quot;</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                pc.consumer();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;Consumer&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object LOCK = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">produce</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Produce-&gt;&quot;</span> + (i++));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">consumer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Consumer-&gt;&quot;</span> + (i));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这种模型当生产者和消费者启动后会发现两个线程无法协作，生产者不断生产，消费者<code>不消费</code>或者<code>重复消费</code></p>
<p><strong>单生产者&amp;单消费者</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProduceConsumerVersion2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ProduceConsumerVersion2 pc = <span class="keyword">new</span> ProduceConsumerVersion2();</span><br><span class="line">        Stream.of(<span class="string">&quot;Produce1&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    pc.produce();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, n).start();</span><br><span class="line">        &#125;);</span><br><span class="line">        Stream.of(<span class="string">&quot;Consumer1&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    pc.consumer();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, n).start();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object LOCK = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> isProduced = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">produce</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            <span class="keyword">if</span> (isProduced) &#123;</span><br><span class="line">                <span class="comment">//已经生产了</span></span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    LOCK.wait();<span class="comment">//等待消费者唤醒</span></span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;--&gt;&quot;</span> + (++i));<span class="comment">//produce</span></span><br><span class="line">            isProduced = <span class="keyword">true</span>;</span><br><span class="line">            LOCK.notify();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">consumer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!isProduced) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    LOCK.wait();<span class="comment">//等待生产者唤醒</span></span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;--&gt;&quot;</span> + (i));<span class="comment">//consumer</span></span><br><span class="line">            isProduced = <span class="keyword">false</span>;</span><br><span class="line">            LOCK.notify();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>wait()：</strong> 当前线程<code>释放锁</code>进入该锁对象的<code>等待队列</code> </p>
<blockquote>
<p>Causes the current thread to wait until another thread invokes the</p>
<p>{@link java.lang.Object#notify()} method or the</p>
<p>{@link java.lang.Object#notifyAll()} method for this object.</p>
<p>In other words, this method behaves exactly as if it simply</p>
<p>performs the call {@code <code>wait(0)</code>}.</p>
<p>The current thread <code>must own this object&#39;s monitor.</code> The thread</p>
<p><code>releases</code> ownership of this monitor and waits until another thread</p>
<p>notifies threads waiting on this object’s monitor to wake up</p>
<p>either through a call to the {@code notify} method or the</p>
<p>{@code notifyAll} method. The thread then waits until it can</p>
<p>re-obtain ownership of the monitor and resumes execution.</p>
</blockquote>
<p><strong>wait(long timeout)：</strong><code>wait()</code>的重载方法很容易想到是干啥的✔</p>
<blockquote>
<p>Causes the current thread to wait until either another thread invokes the</p>
<p>{@link java.lang.Object#notify()} method or the</p>
<p>{@link java.lang.Object#notifyAll()} method for this object, or a</p>
<p><code>specified amount of time has elapsed.</code></p>
<p>The current thread must own this object’s monitor.</p>
<p>@throws  <code>IllegalArgumentException</code>  if the value of timeout is negative.</p>
</blockquote>
<p><strong>notify()：</strong> 唤醒该<code>锁对象</code>的<code>等待队列</code>的线程，唤醒方法不同的虚拟机实现不同有的可能是<code>FCFS</code>有的可能是<code>SJF</code> 等等….所以唤醒的是那个线程是无法确定的</p>
<blockquote>
<p>Wakes up a single thread that is <code>waiting on this object&#39;s</code></p>
<p><code>monitor</code>. If any threads are waiting on this object, one of them</p>
<p>is chosen to be awakened. <code>The choice is arbitrary and occurs at</code></p>
<p><code>the discretion of the implementation</code>. A thread waits on an object’s</p>
<p>monitor by calling one of the {@code wait} methods.</p>
<p>The awakened thread will not be able to proceed until the current</p>
<p>thread <code>relinquishes</code> the lock on this object. The awakened thread will</p>
<p>compete in the usual manner with any other threads that might be</p>
<p>actively competing to synchronize on this object; for example, the</p>
<p>awakened thread enjoys no reliable privilege or disadvantage in being</p>
<p>the next thread to lock this object.</p>
</blockquote>
<p>生产者生产一个消费者消费一个，没毛病，但是上面的代码仅仅适用于<code>单生产者&amp;消费者</code>对于多个生产者消费者就会有线程安全问题，具体问题如下</p>
<p><strong>测试多消费者&amp;生产者</strong></p>
<p>沿用上面single p&amp;c的代码，测试多消费者和生产者</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    ProduceConsumerVersion3 pc = <span class="keyword">new</span> ProduceConsumerVersion3();</span><br><span class="line">    Stream.of(<span class="string">&quot;Produce1&quot;</span>, <span class="string">&quot;Produce2&quot;</span>, <span class="string">&quot;Produce3&quot;</span>, <span class="string">&quot;Produce4&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                pc.produce();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, n).start();</span><br><span class="line">    &#125;);</span><br><span class="line">    Stream.of(<span class="string">&quot;Consumer1&quot;</span>, <span class="string">&quot;Consumer2&quot;</span>, <span class="string">&quot;Consumer3&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                pc.consumer();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, n).start();</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行会发现程序进入<code>”死锁“</code>状态，用<code>jps&amp;jstack</code>分析</p>
<p><img  
                     lazyload
                     src="/images/loading.svg"
                     data-src="http://static.imlgw.top///20190328/pzXBY0ertEVV.png?imageslim"
                      alt="mark"
                ></p>
<p>程序并没有发现死锁❎，这就是多生产者多消费者会产生的<code>假死</code>状态，实际上是所有的线程都进入了<code>wait()</code>状态都放弃了<code>CPU</code>的执行权</p>
<p><strong>假死原因分析</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Produce1--&gt;<span class="number">1</span>	notify C1 wait</span><br><span class="line">Consumer1--&gt;<span class="number">1</span>	notify P1 wait</span><br><span class="line">Produce1--&gt;<span class="number">2</span>    notify C2 wait</span><br><span class="line">Consumer2--&gt;<span class="number">2</span>   notify P2 wait</span><br><span class="line">Produce2--&gt;<span class="number">3</span>	notify P1 wait ---&gt; Produce1--&gt;wait</span><br></pre></td></tr></table></figure>

<p>上面是其中一种情况，大致分析下：前两次生产消费都正常一个<code>消费者</code>唤醒一个<code>生产者</code>，前两次执行完之后<code>P1 C1 C2</code>都进入<code>wait</code>状态然后第三次生产的时候<code>P2</code>唤醒了一个不该唤醒的人😂 唤醒了<code>P1</code>然后<code>wait</code>了，<code>P1</code>醒来后发现已经生产了然后也<code>wait</code>去了，至此所有的线程全部进入<code>wait</code>状态就造成了假死。这个问题记得大一的时候还问过老师当时特别纠结为啥会死锁，现在看看其实也没啥，主要就是<code>notify</code>唤醒的线程是不确定的，是由<code>JVM</code>决定的每种<code>JDK</code>的实现也不太一样，无法保证消费者一定唤醒生产者，反之亦然。</p>
<p><strong>多生产者&amp;多消费者</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.stream.Stream;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProduceConsumerVersion3</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ProduceConsumerVersion3 pc = <span class="keyword">new</span> ProduceConsumerVersion3();</span><br><span class="line">        Stream.of(<span class="string">&quot;Produce1&quot;</span>, <span class="string">&quot;Produce2&quot;</span>, <span class="string">&quot;Produce3&quot;</span>, <span class="string">&quot;Produce4&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    pc.produce();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, n).start();</span><br><span class="line">        &#125;);</span><br><span class="line">        Stream.of(<span class="string">&quot;Consumer1&quot;</span>, <span class="string">&quot;Consumer2&quot;</span>, <span class="string">&quot;Consumer3&quot;</span>).forEach(n -&gt; &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    pc.consumer();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, n).start();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object LOCK = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> isProduced = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">produce</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            <span class="keyword">while</span> (isProduced) &#123;</span><br><span class="line">                <span class="comment">//已经生产了</span></span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    LOCK.wait(); <span class="comment">//加入LOCK锁的wait队列</span></span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;--&gt;&quot;</span> + (++i));<span class="comment">//produce</span></span><br><span class="line">            isProduced = <span class="keyword">true</span>;</span><br><span class="line">            LOCK.notifyAll();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">consumer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (LOCK) &#123;</span><br><span class="line">            <span class="keyword">while</span> (!isProduced) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    LOCK.wait();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;--&gt;&quot;</span> + (i));<span class="comment">//consumer</span></span><br><span class="line">            isProduced = <span class="keyword">false</span>;</span><br><span class="line">            LOCK.notifyAll();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>notifyAll()：</strong>唤醒当前锁对象等待队列上的<code>所有</code>线程</p>
<blockquote>
<p>Wakes up <code>all threads</code> that are waiting on <code>this object&#39;s monitor</code>. A</p>
<p>thread waits on an object’s monitor by calling one of the</p>
<p>{@code wait} methods.</p>
<p>The awakened threads will not be able to proceed until the current</p>
<p>thread relinquishes the lock on this object. The awakened threads</p>
<p>will <code>compete in the usual manner</code> with any other threads that might</p>
<p>be actively competing to synchronize on this object; for example,</p>
<p>the awakened threads enjoy <code>no reliable privilege or disadvantage</code> in</p>
<p>being the next thread to lock this object.</p>
</blockquote>
<p>① 为了解决上面的<code>假死</code>问题这里使用了<code>notifyAll()</code>来唤醒<code>等待队列</code>的线程，看名字就知道这个方法会唤醒所有的线程，那么上面的假死问题就自然解决了。</p>
<p>② 还有一点不同的是这里判断生产状态时用的是<code>while</code>而不是<code>if</code>为什么不用<code>if</code>? 其实也很好理解如果有多个生产者或者消费者同时在<code>等待队列</code>中，然后其中一个抢到锁后执行，执行完生产后唤醒了所有等待的线程，假设唤醒的是<code>生产者</code>的话，因为是<code>if语句</code>控制的被唤醒的生产者抢到锁之后就直接顺着执行下去了，就直接去生产了，就会造成<code>重复的生产</code>当然用<code>else</code>语句貌似可以解决这个问题，但是那会影响效率（个人感觉），而且很别扭（被唤醒了直接退出？？？）. 所以这里用<code>while</code>来进行<code>二次检测</code>避免这种情况，这种while循环也被称为<code>自旋锁</code> 这一块后面的文章会再详细的讲。</p>
<h3 id="为什么wait和notify必须在同步方法或同步块中调用？"><a href="#为什么wait和notify必须在同步方法或同步块中调用？" class="headerlink" title="为什么wait和notify必须在同步方法或同步块中调用？"></a>为什么wait和notify必须在同步方法或同步块中调用？</h3><p>这是<code>阿里巴巴</code>的一道面试题</p>
<p>① 首先从语法层面讲，如果不在同步方法和同步代码块中调用，也就是说没有加锁，自然就不用谈是不是<code>锁对象的持有者</code> ，就会报<code>IllegalMonitorStateException</code>.</p>
<blockquote>
<p>@throws  <code>IllegalMonitorStateException</code>  if the current thread is not</p>
<p>the owner of the object’s monitor.</p>
</blockquote>
<p>②设想下如果不加锁可以直接调用，就会产生所谓的<code>竞态条件</code>，假设<code>wait()</code>,<code>notify()</code>,<code>notifyAll()</code>方法不需要加锁就能够被调用。此时消费者线程调用<code>wait()</code>正在进入状态变量的等待队列(译者注:可能还未进入)。在同一时刻，生产者线程调用<code>notify()</code>方法打算向消费者线程通知状态改变。那么此时消费者线程将错过这个通知并一直阻塞。因此，对象的<code>wait()</code>,<code>notify()</code>,<code>notifyAll()</code>方法必须在该对象的同步方法或同步代码块中被互斥地调用。</p>
<blockquote>
<p>计算的正确性取决于多个线程的交替执行时序时就会产生竞态条件</p>
</blockquote>
<h3 id="wait-后被唤醒会怎么样？"><a href="#wait-后被唤醒会怎么样？" class="headerlink" title="wait()后被唤醒会怎么样？"></a>wait()后被唤醒会怎么样？</h3><p>上面说到被唤醒后会去抢锁，但是这里有人可能会有疑问，去抢锁会不会回到同步的起点去争抢锁，然后把wait前的逻辑再执行一遍？这里肯定事不会的，确实是要抢锁但是会有记录会继续顺着wait方法走下去。</p>
<h3 id="notify和中断的一个很有意思的现象"><a href="#notify和中断的一个很有意思的现象" class="headerlink" title="notify和中断的一个很有意思的现象"></a>notify和中断的一个很有意思的现象</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NotifyInter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> a = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        Object object = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">        NotifyInter waitNotify = <span class="keyword">new</span> NotifyInter();</span><br><span class="line"></span><br><span class="line">        Thread thread1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程1 获取到监视器锁&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        object.wait();</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 正常恢复啦。但是 isInterrupt = &quot;</span>+ Thread.currentThread().isInterrupted());</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 wait方法抛出了InterruptedException异常&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程1&quot;</span>);</span><br><span class="line">        thread1.start();</span><br><span class="line"></span><br><span class="line">        Thread thread2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程2 获取到监视器锁&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        object.wait();</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程2 正常恢复啦。&quot;</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程2 wait方法抛出了InterruptedException异常&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程2&quot;</span>);</span><br><span class="line">        thread2.start();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 这里让 thread1 和 thread2 先起来，然后再起后面的 thread3</span></span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 拿到了监视器锁。&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 设置线程1中断&quot;</span>);</span><br><span class="line">                    thread1.interrupt(); <span class="comment">// 1</span></span><br><span class="line">                    <span class="comment">//waitNotify.a = 1; // 这行是为了禁止上下的两行中断和notify代码重排序</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 调用notify&quot;</span>);</span><br><span class="line">                    object.notify(); <span class="comment">//2</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 调用完notify后，休息一会&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 休息够了，结束同步代码块&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程3&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>多执行几次可能就可能会发生如下情况，线程1被打断后居然正常的返回了！！！！线程2被阻塞住了</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">线程<span class="number">1</span> 获取到监视器锁</span><br><span class="line">线程<span class="number">2</span> 获取到监视器锁</span><br><span class="line">线程<span class="number">3</span> 拿到了监视器锁。</span><br><span class="line">线程<span class="number">3</span> 设置线程<span class="number">1</span>中断</span><br><span class="line">线程<span class="number">3</span> 调用notify</span><br><span class="line">线程<span class="number">3</span> 调用完notify后，休息一会</span><br><span class="line">线程<span class="number">3</span> 休息够了，结束同步代码块</span><br><span class="line">线程<span class="number">1</span> 正常恢复啦。但是 isInterrupt = <span class="keyword">true</span></span><br></pre></td></tr></table></figure>

<p>其实这里主要问题就是 <code>notify()</code> 和<code>interrupt()</code> 执行顺序的问题</p>
<ul>
<li><p>如果先被打断，那么后续的notify会这个线程无效，依然会抛出异常，如果这是该锁实例上仍然有其他线程处于wait状态，那么这个notify会唤醒其中的一个，不能虚发，具体可以参考 <a class="link"   target="_blank" rel="noopener" href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.2.4" >Java语言规范文档17.2.4<i class="fas fa-external-link-alt"></i></a></p>
<blockquote>
<p>The above specifications allow us to determine several properties having to do with the interaction of waits, notification, and interruption.</p>
<p>If a thread is both notified and interrupted while waiting, it may either:</p>
<ul>
<li>return normally from <code>wait</code>, while still having a pending interrupt (in other words, a call to <code>Thread.interrupted</code> would return true)</li>
<li>return from <code>wait</code> by throwing an <code>InterruptedException</code></li>
</ul>
<p>The thread may not reset its interrupt status and return normally from the call to <code>wait</code>.</p>
<p>Similarly, notifications cannot be lost due to interrupts. Assume that a set <em>s</em> of threads is in the wait set of an object <em>m</em>, and another thread performs a <code>notify</code> on <em>m</em>. Then either:</p>
<ul>
<li>at least one thread in <em>s</em> must return normally from <code>wait</code>, or</li>
<li>all of the threads in <em>s</em> must exit <code>wait</code> by throwing <code>InterruptedException</code></li>
</ul>
<p>Note that if a thread is both interrupted and woken via <code>notify</code>, and that thread returns from <code>wait</code> by throwing an <code>InterruptedException</code>, then some other thread in the wait set must be notified.</p>
</blockquote>
</li>
<li><p>如果先被notify()，那么线程会从wait中醒来，然后中断，设置中断标志位为 true，但不会在这个wait上抛出异常，而会影响后面的阻塞操作，具体可以看下面的Demo</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NotifyInter</span> </span>&#123;</span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> a = <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Object object = <span class="keyword">new</span> Object();</span><br><span class="line">        NotifyInter waitNotify = <span class="keyword">new</span> NotifyInter();</span><br><span class="line">        Thread thread1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程1 获取到监视器锁&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        object.wait();</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 正常恢复啦。但是 isInterrupt = &quot;</span>+ Thread.currentThread().isInterrupted());</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;线程1 wait方法抛出了InterruptedException异常&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                        System.out.println(<span class="string">&quot;在sleep中被中断&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程1&quot;</span>);</span><br><span class="line">        thread1.start();</span><br><span class="line">        <span class="comment">// 这里让 thread1 和 thread2 先起来，然后再起后面的 thread3</span></span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (object) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 拿到了监视器锁。&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 设置线程1中断&quot;</span>);</span><br><span class="line">                    object.notify(); <span class="comment">//2</span></span><br><span class="line">                    waitNotify.a = <span class="number">1</span>; <span class="comment">// 这行是为了禁止上下的两行中断和notify代码重排序</span></span><br><span class="line">                    thread1.interrupt(); <span class="comment">// 1</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 调用notify&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 调用完notify后，休息一会&quot;</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;线程3 休息够了，结束同步代码块&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">&quot;线程3&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="wait-和sleep-的区别"><a href="#wait-和sleep-的区别" class="headerlink" title="wait()和sleep()的区别"></a>wait()和sleep()的区别</h3><p>这也是一道面试常问的题</p>
<p>① 首先<code>sleep()</code>是线程Thread的静态方法，<code>wait()</code>是<code>Object</code>类的实例方法</p>
<p>②<code>sleep()</code>不会释放锁对象，<code>wait()</code>会释放锁对象，这一点比较重要</p>
<p>③ 承接第二点，<code>wait()</code>会释放锁，但是要是你没有锁呢？其实就是上面语法层面说到的，所以调用<code>wait()</code>必须要<code>持有</code>锁对象否则就会报<code>IllegalMonitorStateException</code></p>
<p>④<code>sleep()</code>不需要被唤醒<code>timeout</code>后会自动醒来，而<code>wait()</code>需要被其他线程唤醒（<code>wait(long time)</code>除外）</p>
<h3 id="线程通讯综合案例"><a href="#线程通讯综合案例" class="headerlink" title="线程通讯综合案例"></a>线程通讯综合案例</h3><p>控制同一时间执行同一方法线程的数量</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ControlThreadNum</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> LinkedList THREADS = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_THREAD = <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> start = System.currentTimeMillis();</span><br><span class="line">        List&lt;Thread&gt; worker = <span class="keyword">new</span> ArrayList();</span><br><span class="line">        <span class="comment">//创建了十个线程，但是控制每次最多同时运行的只有5个</span></span><br><span class="line">        Arrays.asList(<span class="string">&quot;M1&quot;</span>, <span class="string">&quot;M2&quot;</span>, <span class="string">&quot;M3&quot;</span>, <span class="string">&quot;M4&quot;</span>, <span class="string">&quot;M5&quot;</span>, <span class="string">&quot;M6&quot;</span>, <span class="string">&quot;M7&quot;</span>, <span class="string">&quot;M8&quot;</span>, <span class="string">&quot;M9&quot;</span>, <span class="string">&quot;M10&quot;</span>).stream().map(ControlThreadNum::captureThread).forEach(t -&gt; &#123;</span><br><span class="line">            t.start();</span><br><span class="line">            worker.add(t);</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">//main线程等待worker的线程都执行完</span></span><br><span class="line">        worker.stream().forEach(thread -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                thread.join();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        Optional.of(<span class="string">&quot;All capture is done&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">        Optional.of(System.currentTimeMillis() - start).ifPresent(System.out::println);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Thread <span class="title">captureThread</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            Optional.of(<span class="string">&quot;Thread &quot;</span> + Thread.currentThread().getName() + <span class="string">&quot;  is begin&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">            <span class="keyword">synchronized</span> (THREADS) &#123;</span><br><span class="line">                <span class="keyword">while</span> (THREADS.size() &gt;= MAX_THREAD) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        THREADS.wait();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//THREADS 只是用来控制数量&amp;锁 元素是什么并不重要</span></span><br><span class="line">                THREADS.addLast(<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//到这里是并行</span></span><br><span class="line">            Optional.of(<span class="string">&quot;Thread &quot;</span> + Thread.currentThread().getName() + <span class="string">&quot;  is running&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">10000</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">synchronized</span> (THREADS) &#123;</span><br><span class="line">                Optional.of(<span class="string">&quot;Thread &quot;</span> + Thread.currentThread().getName() + <span class="string">&quot;  is end&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">                THREADS.removeLast();</span><br><span class="line">                THREADS.notifyAll();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里一开始一共创建了10个线程，但是执行的时候会控制<code>running</code>的个数小于5个，<code>runnning</code>线程个数用一个<code>LinkList</code>记录，若<code>size()&gt;=5</code>就进入<code>wait</code>然后如果有线程<code>end</code>就会<code>notifyAll</code>唤醒进入等待状态的线程。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Thread M2  is begin</span><br><span class="line">Thread M3  is begin</span><br><span class="line">Thread M2  is running</span><br><span class="line">Thread M1  is begin</span><br><span class="line">Thread M1  is running</span><br><span class="line">Thread M3  is running</span><br><span class="line">Thread M4  is begin</span><br><span class="line">Thread M4  is running</span><br><span class="line">Thread M5  is begin</span><br><span class="line">Thread M6  is begin</span><br><span class="line">Thread M5  is running</span><br><span class="line">Thread M7  is begin</span><br><span class="line">Thread M8  is begin</span><br><span class="line">Thread M9  is begin</span><br><span class="line">Thread M10  is begin</span><br><span class="line">Thread M3  is `end`</span><br><span class="line">Thread M10  is running</span><br><span class="line">Thread M5  is `end`</span><br><span class="line">Thread M1  is `end`</span><br><span class="line">Thread M2  is `end`</span><br><span class="line">Thread M4  is `end`</span><br><span class="line">Thread M6  is running</span><br><span class="line">Thread M7  is running</span><br><span class="line">Thread M9  is running</span><br><span class="line">Thread M8  is running</span><br><span class="line">Thread M10  is end</span><br><span class="line">Thread M8  is end</span><br><span class="line">Thread M9  is end</span><br><span class="line">Thread M7  is end</span><br><span class="line">Thread M6  is end</span><br><span class="line">All capture is done</span><br><span class="line"><span class="number">20124</span></span><br></pre></td></tr></table></figure>

<p>这样就是其实就是为了提高效率，线程并不是越多越好，线程创建太多，就会达到瓶颈，效率反而会降低，因为时间都消耗在了<code>线程切换</code>上了，当然这是在没有<code>线程池</code>的情况下，后面用<code>线程池</code>就不会这么麻烦了。</p>
<h3 id="wait-notify的开销及问题"><a href="#wait-notify的开销及问题" class="headerlink" title="wait()/notify的开销及问题"></a>wait()/notify的开销及问题</h3><p><strong>过早唤醒</strong> </p>
<p> 比如生产者消费者问题中生产者生产后唤醒了生产者，其实就是过早唤醒了，过早唤醒使得那些本来无须被唤醒的等待线程也被唤醒了，从而造成资源浪费。这就好比你在人群里大喊一声“美女”，便会有许多自我感觉良好的女性回头一样——尽管你要喊的仅仅是其中某一个人，但大家却都以为你是在喊自己。过早唤醒问题可以利用JDK<br>1.5引入的<code>java.util.concurrent.locks.Condition</code>接口来解决，后面的文章会讲到。</p>
<p><strong>信号丢失</strong></p>
<p>信号丢失（Missed Signal）问题。如果等待线程在执行<code>Object.wait()</code>前没有先判断保护条件是否已然成立，那么有可能出现这种情形——通知线程在该等待线程进人临界区之前就已经更新了相关共享变量，使得相应的保护条件成立并进行了通知，但是此时等待线程还没有被暂停，自然也就无所谓唤醒了。这就可能造成等待线程直接执行<code>Object.wait()</code>而被暂停的时候，该线程由于没有其他线程进行通知而一直处于等待状态。这种现象就相当于等待线程错过了一个本来“发送”给它的“信号”，因此被称为信号丢失（Missed Signal）。只要将对保护条件的判断和<code>Object.wait()</code>调用放在一个循环语句之中就可以避免上述场景的信号丢失。信号丢失的另外一个表现是在应该调用<code>Object.notifyAll()</code> 的地方却调用了<code>Object.notify()</code>。比如，对于使用同一个保护条件的多个等待线程，如果通知线程在侦测到这个保护条件成立后调用的是<code>Object.notify()</code>，那么这些等待线程最多只有一个线程能够被唤醒，甚至一个也没有被唤醒——被唤醒的线程是<code>Object.notify()</code>所属对象上使用其他保护条件的一个等待线程！也就是说，尽管通知线程在调用<code>Object.notify()</code>前可能考虑（判断）了某个特定的保护条件是否成立，但是<code>Object.notify()</code>本身在其唤醒线程时是不考虑任何保护条件的！这就可能使得通知线程执行<code>Object.notify()</code>进行的通知对于使用相应保护条件的等待线程来说丢失了。这种情形下，避免信号丢失的一个方法是在必要的时候使用<code>Object.notifyAll()</code>来通知。总的来说，信号丢失本质上是一种代码错误，而不是Java标准库API自身的问题。</p>
<p><strong>欺骗性唤醒</strong></p>
<p>由于莫名其妙的原因，线程有可能在没有调用过<code>notify()</code>和<code>notifyAll()</code>的情况下醒来。这就是所谓的假唤醒（spurious wakeups），无端端地醒过来了，然而此时可能保护条件并没有成立。这个问题的解决同样是讲 保护条件和wait放在临界区内同一个循环体内就可以了。</p>
<p><strong>上下文切换</strong></p>
<p>​    首先，等待线程执行<code>Object.wait()</code>至少会导致该线程对相应对象内部锁的两次申请与释放。通知线程在执行<code>Object.notify()/notifyAll()</code>时需要持有相应对象的内部锁，因此<code>Object.notify()/notifyAll()</code>调用会导致一次锁的申请。而锁的申请与释放可能导致上下文切换。</p>
<p>​    其次，等待线程从被暂停到唤醒这个过程本身就会导致上下文切换。</p>
<p>​    再次，被唤醒的等待线程在继续运行时需要再次申请相应对象的内部锁，此时等待线程可能需要和相应对象的入口集中的其他线程以及其他新来的活跃线程（即申请相应的内部锁且处于RUNNABLE状态的线程）争用相应的内部锁，而这又可能导致上下文切换。<br>最后，过早唤醒问题也会导致额外的上下文切换，这是因为被过早唤醒的线程仍然需要继续等待，即再次经历被暂停和唤醒的过程。</p>
<p><a class="link"   target="_blank" rel="noopener" href="http://ifeve.com/thread-signaling/" >更多参考<i class="fas fa-external-link-alt"></i></a></p>
<h2 id="13-手写一个BooleanLock"><a href="#13-手写一个BooleanLock" class="headerlink" title="13.手写一个BooleanLock"></a>13.手写一个BooleanLock</h2><p><code>Synchronized</code>的缺点其实很明显，当多个线程竞争锁的时候，当一个线程抢到锁后其他的线程只能傻傻的等着，这样会影响效率，所以这里可以自己简单手写一个限制等待时间的锁。</p>
<h3 id="LOCK接口"><a href="#LOCK接口" class="headerlink" title="LOCK接口"></a>LOCK接口</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Lock</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">TimeOutException</span> <span class="keyword">extends</span> <span class="title">Exception</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">TimeOutException</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(message);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">lock</span><span class="params">(<span class="keyword">long</span> time)</span> <span class="keyword">throws</span> InterruptedException,TimeOutException</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">unLock</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function">Collection&lt;Thread&gt; <span class="title">getBlockThread</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>定义了一个<code>TimeOutException</code></p>
<h3 id="BooleanLock实现类"><a href="#BooleanLock实现类" class="headerlink" title="BooleanLock实现类"></a>BooleanLock实现类</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BooleanLock</span> <span class="keyword">implements</span> <span class="title">Lock</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//false indicated free</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> initValue;</span><br><span class="line">    <span class="comment">//加锁的线程</span></span><br><span class="line">    <span class="keyword">private</span> Thread lockedThread;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Collection&lt;Thread&gt; blockThreadCollection = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BooleanLock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.initValue = <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (initValue) &#123;</span><br><span class="line">            blockThreadCollection.add(Thread.currentThread());</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; is wait&quot;</span>);</span><br><span class="line">            <span class="keyword">this</span>.wait();</span><br><span class="line">        &#125;</span><br><span class="line">        blockThreadCollection.remove(Thread.currentThread());</span><br><span class="line">        <span class="keyword">this</span>.initValue = <span class="keyword">true</span>;</span><br><span class="line">        <span class="keyword">this</span>.lockedThread = Thread.currentThread();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">(<span class="keyword">long</span> time)</span> <span class="keyword">throws</span> InterruptedException, TimeOutException </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (time &lt;= <span class="number">0</span>) lock();</span><br><span class="line">        <span class="keyword">long</span> remainTime=time;</span><br><span class="line">        <span class="keyword">long</span> endTime=System.currentTimeMillis()+time;</span><br><span class="line">        <span class="keyword">while</span> (initValue)&#123;</span><br><span class="line">            <span class="keyword">if</span>(remainTime&lt;=<span class="number">0</span>)&#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> TimeOutException(<span class="string">&quot;time is out&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            blockThreadCollection.add(Thread.currentThread());</span><br><span class="line">            <span class="keyword">this</span>.wait(time);</span><br><span class="line">            remainTime=endTime-System.currentTimeMillis();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.initValue=<span class="keyword">true</span>;</span><br><span class="line">        <span class="keyword">this</span>.lockedThread=Thread.currentThread();</span><br><span class="line">        blockThreadCollection.remove(Thread.currentThread());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">unLock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//判断是不是加锁的线程</span></span><br><span class="line">        <span class="keyword">if</span> (lockedThread == Thread.currentThread()) &#123;</span><br><span class="line">            <span class="keyword">this</span>.initValue = <span class="keyword">false</span>;</span><br><span class="line">            <span class="keyword">this</span>.notifyAll();</span><br><span class="line">            Optional.of(Thread.currentThread().getName() + <span class="string">&quot;  release the lock monitor&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Collection&lt;Thread&gt; <span class="title">getBlockThread</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Collections.unmodifiableCollection(blockThreadCollection);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="测试BooleanLock的效果"><a href="#测试BooleanLock的效果" class="headerlink" title="测试BooleanLock的效果"></a>测试BooleanLock的效果</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LockTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> BooleanLock booleanLock = <span class="keyword">new</span> BooleanLock();</span><br><span class="line">        Stream.of(<span class="string">&quot;t0&quot;</span>, <span class="string">&quot;t1&quot;</span>, <span class="string">&quot;t2&quot;</span>).forEach(name -&gt; &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    booleanLock.lock(<span class="number">10</span>);</span><br><span class="line">                    Optional.of(Thread.currentThread().getName() + <span class="string">&quot; get the lock&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">                    doSomething();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Lock.TimeOutException e) &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName()+<span class="string">&quot; Time out&quot;</span>);</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                    booleanLock.unLock();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, name).start();</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">//main线程释放锁，不应该，谁加的锁应该由谁去释放锁</span></span><br><span class="line">        <span class="comment">//booleanLock.unLock();</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">doSomething</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Optional.of(Thread.currentThread().getName() + <span class="string">&quot; is working...&quot;</span>).ifPresent(System.out::println);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里设置在抢不到锁的时候，只等待<code>10ms</code>，然后<code>doSomething</code>会<code>sleep</code>5000ms，所以只有一个线程可以抢到锁后面的都会超时 throw <code>TimeOutException</code>典型的<code>限时等待</code>模型</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">t0 get the lock</span><br><span class="line">t0 is working...</span><br><span class="line">`base_thread_study.chaper10.Lock$TimeOutException: time is out`</span><br><span class="line">	at base_thread_study.chaper10.BooleanLock.lock(BooleanLock.java:<span class="number">41</span>)</span><br><span class="line">	at base_thread_study.chaper10.LockTest.lambda$<span class="keyword">null</span>$<span class="number">0</span>(LockTest.java:<span class="number">12</span>)</span><br><span class="line">	at java.lang.Thread.run(Thread.java:<span class="number">748</span>)</span><br><span class="line">`base_thread_study.chaper10.Lock$TimeOutException: time is out`</span><br><span class="line">	at base_thread_study.chaper10.BooleanLock.lock(BooleanLock.java:<span class="number">41</span>)</span><br><span class="line">	at base_thread_study.chaper10.LockTest.lambda$<span class="keyword">null</span>$<span class="number">0</span>(LockTest.java:<span class="number">12</span>)</span><br><span class="line">	at java.lang.Thread.run(Thread.java:<span class="number">748</span>)</span><br><span class="line">t2 Time out</span><br><span class="line">t1 Time out</span><br><span class="line">t0  release the lock monitor</span><br></pre></td></tr></table></figure>

<h2 id="14-给应用程序注入钩子Hook"><a href="#14-给应用程序注入钩子Hook" class="headerlink" title="14.给应用程序注入钩子Hook"></a>14.给应用程序注入钩子Hook</h2><p>关于<code>Hook</code>是什么就不多介绍了，这里的钩子和<code>git</code>,<code>svn</code>里面的是一样的，类似的在使用<code>Tomcat</code>等服务的时候，在你关闭它之后它仍然会打印日志和释放一些资源，这就是<code>Hook</code>的一种，当然<code>Hook</code>有多种，这只是其中一种。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExitCap</span></span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String []arg)</span></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> i=<span class="number">0</span>;</span><br><span class="line">	Runtime.getRuntime().addShutdownHook(<span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">   	    System.out.println(<span class="string">&quot;The test app will shutdown&quot;</span>);</span><br><span class="line">	    notifyAndRelease();</span><br><span class="line">	&#125;));</span><br><span class="line">	<span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">		<span class="keyword">try</span>&#123;</span><br><span class="line">		Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">		System.out.println(<span class="string">&quot;i am working&quot;</span>);</span><br><span class="line">		&#125;<span class="keyword">catch</span>(Exception e)&#123;</span><br><span class="line">		 <span class="comment">//donothing</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">if</span>(i&gt;<span class="number">10</span>)&#123;</span><br><span class="line">		   <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException();</span><br><span class="line">		&#125;</span><br><span class="line">		i++;    </span><br><span class="line">	&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">notifyAndRelease</span><span class="params">()</span></span>&#123;</span><br><span class="line">	System.out.println(<span class="string">&quot;notify to admin&quot;</span>);</span><br><span class="line">    	</span><br><span class="line">	<span class="keyword">try</span>&#123;</span><br><span class="line">	Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">	&#125;<span class="keyword">catch</span>(Exception e)&#123;&#125;</span><br><span class="line">	</span><br><span class="line">	System.out.println(<span class="string">&quot;release the resources(socker. file, connection.)&quot;</span>);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">try</span>&#123;</span><br><span class="line">        Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">        &#125;<span class="keyword">catch</span>(Exception e)&#123;&#125;</span><br><span class="line">	</span><br><span class="line">	System.out.println(<span class="string">&quot;release and notify done&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>这里是在<code>Linux</code>上进行的测试，因为效果比较明显，顺便也熟悉下<code>Linux</code>的命令，可以看到上面的钩子就是通过<code>Runtime.getRuntime().addShutdownHook()</code>注入了一个<code>Thread</code>进去的，这样就会检测到程序的退出并触发<code>Hook</code>做一些释放资源之类的工作。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">i am working</span><br><span class="line">Exception in thread <span class="string">&quot;main&quot;</span> java.lang.RuntimeException</span><br><span class="line">	at base_thread_study.chaper10.ExitCap.main(ExitCap.java:<span class="number">18</span>)</span><br><span class="line">i am working</span><br><span class="line">`The test app will shutdown`</span><br><span class="line">`notify to admin`</span><br><span class="line">`<span class="function">release the <span class="title">resources</span><span class="params">(socker. file, connection.)</span>`</span></span><br><span class="line"><span class="function">`release and notify done`</span></span><br></pre></td></tr></table></figure>

<p>上面是在正常情况下终止线程比如 <code>异常</code>，<code>ctrl C</code>或者 <code>kill pid</code>如果使用 <code>kill -9 pid</code>就不会触发钩子，强制停止，所以一般不建议用<code>kill -9</code></p>
<h2 id="15-捕获线程的Runtime异常"><a href="#15-捕获线程的Runtime异常" class="headerlink" title="15.捕获线程的Runtime异常"></a>15.捕获线程的Runtime异常</h2><p>在Java多线程环境下，所有线程都不允许抛出未捕获的<code>checked exception</code>(比如sleep的InterruptException)，也就是各个线程必须自己把自己的<code>checked exception</code>处理掉，但是如果是<code>unchecked exception </code>呢？主要就是指<code>RuntimeException</code>此类异常抛出时该线程会<code>shutdown</code>但是其它线程不受影响也无法感知到这个异常，就像下面的例子</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadException</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Thread thread = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            thread=<span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">                <span class="keyword">int</span> res=<span class="number">1</span>/<span class="number">0</span>;</span><br><span class="line">            &#125;);</span><br><span class="line">            thread.start();</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;捕获到异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出<code>main线程</code>并没有捕获到异常，其实这也是一种很好的理念，每个线程的事情应该由线程自己去处理不应该由其他线程去干扰，正如<code>stop/resume/suspend</code>这些方法被弃用的原因。但是这些异常如果不去处理可能会导致一些严重的后果，JDK1.5之后官方也提供了API去处理线程的异常。setDefaultUncaughtExceptionHandler()和setUncaughtExceptionHandler()前者是<code>Thread</code>的静态方法，用于给所有的线程设置默认的异常处理，后者是实例方法，针对每个线程会给每个线程加上一个异常处理器，如下Demo</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadException</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> A = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> B = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Thread thread = <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">              <span class="keyword">int</span> res = A / B;</span><br><span class="line">            &#125;</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//最好在start前设置异常处理器，放在后面可能会起不到作用。</span></span><br><span class="line">        thread.setUncaughtExceptionHandler((t, e) -&gt; &#123;</span><br><span class="line">            System.out.println(t.getName());</span><br><span class="line">            System.out.println(e);</span><br><span class="line">        &#125;);</span><br><span class="line">        thread.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>Thread-0</code><br><code>java.lang.ArithmeticException: / by zero</code></p>
</blockquote>
<p>可以看到已经捕获到了这个异常，当线程遇到未捕获的异常而结束时会调用<code>UncaughtExceptionHandler</code> 处理一些”后事”和释放一些宝贵的资源，<code>setUncaughtExceptionHandler</code>建议放在线程start之前，不然可能起不到作用。</p>
<h2 id="16-ThreadGroup线程组"><a href="#16-ThreadGroup线程组" class="headerlink" title="16.ThreadGroup线程组"></a>16.ThreadGroup线程组</h2><h3 id="获取线程组信息"><a href="#获取线程组信息" class="headerlink" title="获取线程组信息"></a>获取线程组信息</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadGroupAPI</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ThreadGroup tgp = <span class="keyword">new</span> ThreadGroup(<span class="string">&quot;TGP1&quot;</span>);</span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(tgp, <span class="string">&quot;t0&quot;</span>) &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        System.out.println(getThreadGroup().getName());</span><br><span class="line">                        System.out.println(getThreadGroup().getParent());</span><br><span class="line">                        <span class="comment">//可以访问，文档上说不行</span></span><br><span class="line">                        System.out.println(getThreadGroup().getParent().activeCount());</span><br><span class="line">                        Thread.sleep(<span class="number">10000</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        t.start();</span><br><span class="line"></span><br><span class="line">        ThreadGroup tgp2 = <span class="keyword">new</span> ThreadGroup(<span class="string">&quot;TGP2&quot;</span>);</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(tgp2, <span class="string">&quot;t0&quot;</span>) &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(tgp.getName());</span><br><span class="line">                System.out.println(tgp.activeCount());</span><br><span class="line">                Thread[] threads=<span class="keyword">new</span> Thread[tgp.activeCount()];</span><br><span class="line">                tgp.enumerate(threads);</span><br><span class="line">                <span class="comment">//也可以访问</span></span><br><span class="line">                Arrays.asList(threads).forEach(System.out::println);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        t1.start();</span><br><span class="line">        <span class="comment">//System.out.println(tgp2.getName());</span></span><br><span class="line">        <span class="comment">//System.out.println(tgp2.getParent().getName());</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>文档上说的不能访问其他线程组的信息，这里测试的几个都可以，可能描述有点问题，<code>线程组</code>的创建类似于<code>线程</code>的创建，如果没有显示的指定线程组都会默认加到父线程的线程组中。</p>
<h3 id="打断线程组interrupt"><a href="#打断线程组interrupt" class="headerlink" title="打断线程组interrupt()"></a>打断线程组interrupt()</h3><blockquote>
<p>Interrupts all threads in this thread group.</p>
<p>First, the <code>checkAccess</code> method of this thread group is</p>
<p>called with no arguments; this may result in a security exception.</p>
<p>This method then calls the <code>interrupt</code> method on all the</p>
<p>threads in this thread group and in <code>all of its subgroups.</code></p>
</blockquote>
<p>打断该线程组里面所有的线程，包括子线程组的线程。</p>
<h3 id="线程组setDaemon"><a href="#线程组setDaemon" class="headerlink" title="线程组setDaemon()"></a>线程组setDaemon()</h3><p>和线程的<code>setDaemon</code>不一样。</p>
<blockquote>
<p>Changes the daemon status of this thread group.</p>
<p>First, the <code>checkAccess</code> method of this thread group is</p>
<p>called with no arguments; this may result in a security exception.</p>
<p>A daemon thread group is <code>automatically</code> <code>destroyed</code> when its last</p>
<p>thread is stopped or its <code>last thread group is destroyed</code>.</p>
</blockquote>
<p>当最后一个线程执行完毕后自动销毁线程组，当然与其对应的也有手动销毁的方法<code>destroy()</code>这个方法如果线程没执行完毕就调用会抛<code>IllegalThreadStateException</code>，其他的方法详细可以参考文档。</p>
<h2 id="17-线程池"><a href="#17-线程池" class="headerlink" title="17.线程池"></a>17.线程池</h2><h3 id="为什么要使用线程池"><a href="#为什么要使用线程池" class="headerlink" title="为什么要使用线程池"></a>为什么要使用线程池</h3><p> 创建和销毁线程开销大，利用好线程池可以避免cpu花费不必要的时间在这上面，从而专注于具体的任务:)</p>
<p>基本的线程池包括下面几部分：</p>
<p>①任务队列</p>
<p>②拒绝策略(抛出异常，直接丢弃，阻塞，临时队列)</p>
<p>③<code>init</code>(<code>min</code>)初始大小</p>
<p>④<code>active</code>中间常态大小</p>
<p>⑤<code>max</code>最大个数，超过就会加到任务队列中，任务队列也满就会执行拒绝策略</p>
<blockquote>
<p>min&lt;=active&lt;=max</p>
</blockquote>
<h3 id="手写线程池"><a href="#手写线程池" class="headerlink" title="手写线程池"></a>手写线程池</h3><h4 id="临时队列"><a href="#临时队列" class="headerlink" title="临时队列"></a>临时队列</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleThreadPool</span> </span>&#123;</span><br><span class="line">    <span class="comment">//线程池大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> size;</span><br><span class="line">    <span class="comment">//默认大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> DEFAULT_SIZE = <span class="number">10</span>;</span><br><span class="line">	<span class="comment">//任务队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> LinkedList&lt;Runnable&gt; TASK_QUEUE = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">	<span class="comment">//线程序号</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> <span class="keyword">int</span> seq = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//线程组</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> ThreadGroup GROUP = <span class="keyword">new</span> ThreadGroup(<span class="string">&quot;Pool_Group&quot;</span>);</span><br><span class="line">	<span class="comment">//线程前缀名</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> String THREAD_PREFIX = <span class="string">&quot;SIMPLE_THREAD_POOL-&quot;</span>;</span><br><span class="line">	<span class="comment">//线程队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> List&lt;MyThread&gt; THREAD_QUEUE = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">(<span class="keyword">int</span> size)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.size = size;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(DEFAULT_SIZE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">            createThreadQueue();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">//暴露对外的接口，提交任务队列</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">submit</span><span class="params">(Runnable runnable)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">            TASK_QUEUE.addLast(runnable);</span><br><span class="line">            <span class="comment">//唤醒线程池中的线程</span></span><br><span class="line">            TASK_QUEUE.notifyAll();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">createThreadQueue</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        MyThread thread = <span class="keyword">new</span> MyThread(GROUP, THREAD_PREFIX + (seq++));</span><br><span class="line">        thread.start();</span><br><span class="line">        THREAD_QUEUE.add(thread);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">enum</span> <span class="title">ThreadState</span> </span>&#123;</span><br><span class="line">        FREE, RUNNING, BLOCKED, DEAD</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">//包装的线程类</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">volatile</span> ThreadState threadState = ThreadState.FREE;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> ThreadState <span class="title">getThreadState</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.threadState;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">MyThread</span><span class="params">(ThreadGroup group, String name)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(group, name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            OUTER:</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">this</span>.threadState != ThreadState.DEAD) &#123;</span><br><span class="line">                <span class="comment">//当前线程没有dead</span></span><br><span class="line">                Runnable runnable;</span><br><span class="line">                <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">                    <span class="keyword">while</span> (TASK_QUEUE.isEmpty()) &#123;</span><br><span class="line">                        <span class="comment">//任务队列为空，全员wait</span></span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">this</span>.threadState = ThreadState.BLOCKED;</span><br><span class="line">                            TASK_QUEUE.wait();</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;break&quot;</span>);</span><br><span class="line">                            <span class="keyword">break</span> OUTER;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                    runnable = TASK_QUEUE.removeFirst();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//这里应该并行</span></span><br><span class="line">                Optional.of(runnable).ifPresent(t -&gt; &#123;</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.RUNNING;</span><br><span class="line">                    t.run();</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.FREE;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.threadState = ThreadState.DEAD;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>最开始实现的时候<code>synchronized</code>的范围太大，将具体的执行<code>run</code>的过程也同步了起来，这明显是有问题的，只需要同步共享变量就可以了，同步了后面的代码那就跟单线程一样了。</p>
<h4 id="关闭线程池-amp-拒绝策略"><a href="#关闭线程池-amp-拒绝策略" class="headerlink" title="关闭线程池&amp;拒绝策略"></a>关闭线程池&amp;拒绝策略</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleThreadPool</span> </span>&#123;</span><br><span class="line">    <span class="comment">//线程池大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> size;</span><br><span class="line">	<span class="comment">//任务队列大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> queueSize;</span><br><span class="line">	<span class="comment">//默认线程池大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> DEFAULT_SIZE = <span class="number">10</span>;</span><br><span class="line">	<span class="comment">//线程池中线程编号</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> <span class="keyword">int</span> seq = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//默认任务队列的大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> DEFAULT_TASK_QUEUE_SIZE = <span class="number">2000</span>;</span><br><span class="line">	<span class="comment">//线程组</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> ThreadGroup GROUP = <span class="keyword">new</span> ThreadGroup(<span class="string">&quot;Pool_Group&quot;</span>);</span><br><span class="line">	<span class="comment">//线程名前缀</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> String THREAD_PREFIX = <span class="string">&quot;SIMPLE_THREAD_POOL-&quot;</span>;</span><br><span class="line">	<span class="comment">//任务队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> LinkedList&lt;Runnable&gt; TASK_QUEUE = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">	<span class="comment">//线程队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> List&lt;MyThread&gt; THREAD_QUEUE = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">	<span class="comment">//拒绝策略</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> DiscardPolicy discardPolicy;</span><br><span class="line">	<span class="comment">//线程次是否销毁</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> destroy = <span class="keyword">false</span>;</span><br><span class="line">	<span class="comment">//默认的拒绝策略（抛异常）</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">static</span> DiscardPolicy DEFAULT_DISCARD_POLICY = () -&gt; &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> DiscardException(<span class="string">&quot;Discard this Task!!!!(Default Policy)&quot;</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">(<span class="keyword">int</span> size, <span class="keyword">int</span> queueSize, DiscardPolicy discardPolicy)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.size = size;</span><br><span class="line">        <span class="keyword">this</span>.queueSize = queueSize;</span><br><span class="line">        <span class="keyword">this</span>.discardPolicy = discardPolicy;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(DEFAULT_SIZE, DEFAULT_TASK_QUEUE_SIZE, DEFAULT_DISCARD_POLICY);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; size; i++) &#123;</span><br><span class="line">            createThreadQueue();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">submit</span><span class="params">(Runnable runnable)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (destroy) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">&quot;The Pool is shutdown , you can&#x27;t submit now ! !&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">            <span class="keyword">if</span> (TASK_QUEUE.size() &gt; queueSize) &#123;</span><br><span class="line">                discardPolicy.discard();</span><br><span class="line">            &#125;</span><br><span class="line">            TASK_QUEUE.addLast(runnable);</span><br><span class="line">            <span class="comment">//唤醒线程池中的线程</span></span><br><span class="line">            TASK_QUEUE.notifyAll();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shutdown</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="comment">//判断任务队列是否为空</span></span><br><span class="line">        <span class="keyword">while</span> (!TASK_QUEUE.isEmpty()) &#123;</span><br><span class="line">            Thread.sleep(<span class="number">50</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> initVal = THREAD_QUEUE.size();</span><br><span class="line">        <span class="keyword">while</span> (initVal &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (MyThread thread : THREAD_QUEUE) &#123;</span><br><span class="line">                <span class="keyword">if</span> (thread.getThreadState() == ThreadState.BLOCKED) &#123;</span><br><span class="line">                    thread.close();</span><br><span class="line">                    thread.interrupt();</span><br><span class="line">                    initVal--;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">10</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.destroy = <span class="keyword">true</span>;</span><br><span class="line">        System.out.println(<span class="string">&quot;My Thread pool is shutdown&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.destroy;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">createThreadQueue</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        MyThread thread = <span class="keyword">new</span> MyThread(GROUP, THREAD_PREFIX + (seq++));</span><br><span class="line">        thread.start();</span><br><span class="line">        THREAD_QUEUE.add(thread);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">enum</span> <span class="title">ThreadState</span> </span>&#123;</span><br><span class="line">        FREE, RUNNING, BLOCKED, DEAD</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DiscardException</span> <span class="keyword">extends</span> <span class="title">RuntimeException</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">DiscardException</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(message);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@FunctionalInterface</span></span><br><span class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DiscardPolicy</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">discard</span><span class="params">()</span> <span class="keyword">throws</span> DiscardException</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">volatile</span> ThreadState threadState = ThreadState.FREE;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> ThreadState <span class="title">getThreadState</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.threadState;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">MyThread</span><span class="params">(ThreadGroup group, String name)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(group, name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            OUTER:</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">this</span>.threadState != ThreadState.DEAD) &#123;</span><br><span class="line">                Runnable runnable;</span><br><span class="line">                <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">                    <span class="keyword">while</span> (TASK_QUEUE.isEmpty()) &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">this</span>.threadState = ThreadState.BLOCKED;</span><br><span class="line">                            TASK_QUEUE.wait();</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; is dead&quot;</span>);</span><br><span class="line">                            <span class="keyword">break</span> OUTER;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                    runnable = TASK_QUEUE.removeFirst();</span><br><span class="line">                &#125;</span><br><span class="line">                Optional.of(runnable).ifPresent(t -&gt; &#123;</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.RUNNING;</span><br><span class="line">                    t.run();</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.FREE;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.threadState = ThreadState.DEAD;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li><code>shutdown</code>方法实现</li>
</ul>
<p>①先轮询任务队列是否为空，不为空就会让<code>当前线程</code>等待<code>线程队列</code>的线程执行完所有任务。</p>
<p>②当任务队列为空时，遍历<code>线程队列</code>，然后打断<code>BLOCK</code>的线程并且设置为<code>DEAD</code>状态跳出循环，因为<code>任务队列</code>为空<code>线程队列</code>里面的线程都会在<code>TASK_QUEUE</code>上面<code>BLOCK</code>住，但是也存在特殊情况，可能某个线程刚拿到最后一个任务，这种情况我们可以稍微等一下，等它<code>BLOCK</code>，毕竟这是个<code>lg(N)-lg(N2)</code>的方法</p>
<p>③设置<code>destory</code>状态为true，然后在<code>submit</code>的时候会根据这个变量来判断是否已经销毁，如果已经销毁就会抛出一个<code>RunntimeException</code></p>
<ul>
<li><code>拒绝策略</code>实现</li>
</ul>
<p>这里实现了一个·默认的拒绝策略，抛出异常，在submit的时候判断任务队列是不是满的，如果满了就直接抛异常，这里如果用这种方式拒绝，一但出现异常<code>当前线程</code>就会<code>直接结束</code>可能就无法关闭连接池。</p>
<h4 id="自动扩容-amp-闲时回收"><a href="#自动扩容-amp-闲时回收" class="headerlink" title="自动扩容&amp;闲时回收"></a>自动扩容&amp;闲时回收</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleThreadPool</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="comment">//线程池大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> size;</span><br><span class="line">    <span class="comment">//线程大小变化值</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> min;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> active;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> max;</span><br><span class="line">    <span class="comment">//默认值</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MIN = <span class="number">4</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> ACTIVE = <span class="number">8</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX = <span class="number">12</span>;</span><br><span class="line">    <span class="comment">//任务队列大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> queueSize;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMin</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> min;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getActive</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> active;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMax</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> max;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//线程池中线程编号</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> <span class="keyword">int</span> seq = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">//默认任务队列的大小</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> DEFAULT_TASK_QUEUE_SIZE = <span class="number">2000</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//线程组</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> ThreadGroup GROUP = <span class="keyword">new</span> ThreadGroup(<span class="string">&quot;Pool_Group&quot;</span>);</span><br><span class="line">    <span class="comment">//线程名前缀</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> String THREAD_PREFIX = <span class="string">&quot;SIMPLE_THREAD_POOL-&quot;</span>;</span><br><span class="line">    <span class="comment">//任务队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> LinkedList&lt;Runnable&gt; TASK_QUEUE = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">    <span class="comment">//线程队列</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> List&lt;MyThread&gt; THREAD_QUEUE = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    <span class="comment">//拒绝策略</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> DiscardPolicy discardPolicy;</span><br><span class="line">    <span class="comment">//线程池是否销毁</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> destroy = <span class="keyword">false</span>;</span><br><span class="line">    <span class="comment">//默认的拒绝策略（抛异常）</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">static</span> DiscardPolicy DEFAULT_DISCARD_POLICY = () -&gt; &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> DiscardException(<span class="string">&quot;Discard this Task!!!!(Default Policy)&quot;</span>);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">(<span class="keyword">int</span> min, <span class="keyword">int</span> active, <span class="keyword">int</span> max, <span class="keyword">int</span> queueSize, DiscardPolicy discardPolicy)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.queueSize = queueSize;</span><br><span class="line">        <span class="keyword">this</span>.discardPolicy = discardPolicy;</span><br><span class="line">        <span class="keyword">this</span>.min = min;</span><br><span class="line">        <span class="keyword">this</span>.active = active;</span><br><span class="line">        <span class="keyword">this</span>.max = max;</span><br><span class="line">        init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleThreadPool</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(MIN, ACTIVE, MAX, DEFAULT_TASK_QUEUE_SIZE, DEFAULT_DISCARD_POLICY);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//线程池的线程，维护整个线程</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (!destroy) &#123;</span><br><span class="line">            System.err.printf(<span class="string">&quot;Pool#min:%d,active:%d,max:%d,currentSize:%d,taskRemain:%d\n&quot;</span>,</span><br><span class="line">                    <span class="keyword">this</span>.min, <span class="keyword">this</span>.active, <span class="keyword">this</span>.max, <span class="keyword">this</span>.size, TASK_QUEUE.size());</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">                <span class="keyword">if</span> (TASK_QUEUE.size() &gt; active &amp;&amp; size &lt; active) &#123;</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">int</span> i = size; i &lt; active; i++) &#123;</span><br><span class="line">                        createThreadQueue();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;increment to active success&quot;</span>);</span><br><span class="line">                    <span class="keyword">this</span>.size = active;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (TASK_QUEUE.size() &gt; max &amp;&amp; size &lt; MAX) &#123;</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">int</span> i = size; i &lt; max; i++) &#123;</span><br><span class="line">                        createThreadQueue();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;increment to max success&quot;</span>);</span><br><span class="line">                    <span class="keyword">this</span>.size = max;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (TASK_QUEUE.isEmpty() &amp;&amp; size &gt; active) &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;==================reduce=================&quot;</span>);</span><br><span class="line">                    <span class="comment">//防止并发修改，在shutdown的时候reduce</span></span><br><span class="line">                    <span class="keyword">synchronized</span> (THREAD_QUEUE) &#123;</span><br><span class="line">                        <span class="keyword">int</span> release = size - active;</span><br><span class="line">                        <span class="comment">//Itertor可以在遍历的过程中remove</span></span><br><span class="line">                        <span class="keyword">for</span> (Iterator&lt;MyThread&gt; it = THREAD_QUEUE.iterator(); it.hasNext(); ) &#123;</span><br><span class="line">                            <span class="keyword">if</span> (release &lt;= <span class="number">0</span>)</span><br><span class="line">                                <span class="keyword">break</span>;</span><br><span class="line">                            MyThread mt = it.next();</span><br><span class="line">                            <span class="comment">//如果该线程在工作就不要打断它</span></span><br><span class="line">                            <span class="keyword">if</span>(mt.getThreadState()==ThreadState.RUNNING)&#123;</span><br><span class="line">                                <span class="keyword">continue</span>;</span><br><span class="line">                            &#125;</span><br><span class="line">                            mt.close();</span><br><span class="line">                            mt.interrupt();</span><br><span class="line">                            it.remove();</span><br><span class="line">                            release--;</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="keyword">this</span>.size = active;</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">/*    for (int i = 0; i &lt; size; i++) &#123;</span></span><br><span class="line"><span class="comment">            createThreadQueue();</span></span><br><span class="line"><span class="comment">        &#125;*/</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="keyword">this</span>.min; i++) &#123;</span><br><span class="line">            createThreadQueue();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.size = min;</span><br><span class="line">        <span class="keyword">this</span>.start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">submit</span><span class="params">(Runnable runnable)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (destroy) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">&quot;The Pool is shutdown , you can&#x27;t submit now ! !&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">            <span class="keyword">if</span> (TASK_QUEUE.size() &gt; queueSize) &#123;</span><br><span class="line">                discardPolicy.discard();</span><br><span class="line">            &#125;</span><br><span class="line">            TASK_QUEUE.addLast(runnable);</span><br><span class="line">            <span class="comment">//唤醒线程池中的线程</span></span><br><span class="line">            TASK_QUEUE.notifyAll();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shutdown</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">while</span> (!TASK_QUEUE.isEmpty()) &#123;</span><br><span class="line">            Thread.sleep(<span class="number">50</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> initVal = THREAD_QUEUE.size();</span><br><span class="line">        <span class="keyword">synchronized</span> (THREAD_QUEUE) &#123;</span><br><span class="line">            <span class="keyword">while</span> (initVal &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="keyword">for</span> (MyThread thread : THREAD_QUEUE) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (thread.getThreadState() == ThreadState.BLOCKED) &#123;</span><br><span class="line">                        <span class="comment">//设置为DEAD状态</span></span><br><span class="line">                        thread.close();</span><br><span class="line">                        thread.interrupt();</span><br><span class="line">                        initVal--;</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        Thread.sleep(<span class="number">10</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.destroy = <span class="keyword">true</span>;</span><br><span class="line">        System.out.println(<span class="string">&quot;My Thread pool is shutdown&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.destroy;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">createThreadQueue</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        MyThread thread = <span class="keyword">new</span> MyThread(GROUP, THREAD_PREFIX + (seq++));</span><br><span class="line">        thread.start();</span><br><span class="line">        THREAD_QUEUE.add(thread);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">enum</span> <span class="title">ThreadState</span> </span>&#123;</span><br><span class="line">        FREE, RUNNING, BLOCKED, DEAD</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">DiscardException</span> <span class="keyword">extends</span> <span class="title">RuntimeException</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">DiscardException</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(message);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@FunctionalInterface</span></span><br><span class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DiscardPolicy</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">discard</span><span class="params">()</span> <span class="keyword">throws</span> DiscardException</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">volatile</span> ThreadState threadState = ThreadState.FREE;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> ThreadState <span class="title">getThreadState</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.threadState;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">MyThread</span><span class="params">(ThreadGroup group, String name)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(group, name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            OUTER:</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">this</span>.threadState != ThreadState.DEAD) &#123;</span><br><span class="line">                Runnable runnable;</span><br><span class="line">                <span class="keyword">synchronized</span> (TASK_QUEUE) &#123;</span><br><span class="line">                    <span class="keyword">while</span> (TASK_QUEUE.isEmpty()) &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">this</span>.threadState = ThreadState.BLOCKED;</span><br><span class="line">                            TASK_QUEUE.wait();</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; is dead&quot;</span>);</span><br><span class="line">                            <span class="keyword">break</span> OUTER;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                    runnable = TASK_QUEUE.removeFirst();</span><br><span class="line">                &#125;</span><br><span class="line">                Optional.of(runnable).ifPresent(t -&gt; &#123;</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.RUNNING;</span><br><span class="line">                    t.run();</span><br><span class="line">                    <span class="keyword">this</span>.threadState = ThreadState.FREE;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.threadState = ThreadState.DEAD;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>相比上面固定的size这个版本</p>
<p>① 增加了三个字段用于动态的扩容，因为需要管理这些线程，所以将整个线程池也继承了<code>Thread</code>并实现了run方法，主要就是判断<code>TASK_QUEUE.size() &gt; active &amp;&amp; size &lt; active</code>当前任务队列任务多于<code>active</code>并且当前线程队列线程数小于<code>active</code>，就可以扩容到active，max同理</p>
<p>②<code>TASK_QUEUE.isEmpty() &amp;&amp; size &gt; active</code> 闲时回收，任务队列没有任务，但是线程队列线程还很多，浪费了资源，所以需要<code>reduce</code>一些空闲的线程。这里有两个小细节，1.在reduce和shutdown的时候需要同步<code>线程队列</code>不然在<code>reduce</code>的时候<code>shutdown</code>会产生<code>并发修改异常</code>（一个在遍历，一个在remove）。</p>
<h3 id="测试线程池"><a href="#测试线程池" class="headerlink" title="测试线程池"></a>测试线程池</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadPoolTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        SimpleThreadPool threadPool= <span class="keyword">new</span> SimpleThreadPool();</span><br><span class="line">        IntStream.rangeClosed(<span class="number">0</span>, <span class="number">40</span>)</span><br><span class="line">                .forEach(i -&gt; &#123;</span><br><span class="line">                    threadPool.submit(() -&gt; &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;The task &quot;</span> + i + <span class="string">&quot;  runnable by thread &quot;</span> + Thread.currentThread().getName() + <span class="string">&quot; start&quot;</span>);</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            e.printStackTrace();</span><br><span class="line">                        &#125;</span><br><span class="line">                        System.out.println(<span class="string">&quot;The task &quot;</span> + i + <span class="string">&quot;  runnable by thread &quot;</span> + Thread.currentThread().getName() + <span class="string">&quot; end&quot;</span>);</span><br><span class="line">                    &#125;);</span><br><span class="line">                    System.out.println(<span class="string">&quot;submit &quot;</span> + i);</span><br><span class="line">                &#125;);</span><br><span class="line">        threadPool.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li>《Java多线程编程实战指南》 </li>
<li><a class="link"   target="_blank" rel="noopener" href="http://ifeve.com/" >并发编程网<i class="fas fa-external-link-alt"></i></a></li>
<li><a class="link"   target="_blank" rel="noopener" href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.2.4" >Java语言规范<i class="fas fa-external-link-alt"></i></a></li>
</ul>

        </div>

        
            <div class="post-copyright-info">
                <div class="article-copyright-info-container">
    <ul>
        <li>本文标题：Java多线程基础</li>
        <li>本文作者：Resolmi</li>
        <li>创建时间：2019-04-07 00:00:00</li>
        <li>
            本文链接：https://imlgw.top/2019/04/07/32b13d92/
        </li>
        <li>
            版权声明：本博客所有文章除特别声明外，均采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">BY-NC-SA</a> 许可协议。转载请注明出处！
        </li>
    </ul>
</div>

            </div>
        

        
            <div class="article-nav">
                
                    <div class="article-prev">
                        <a class="prev"
                           rel="prev"
                           href="/2019/04/09/22c0ee69/"
                        >
                            <span class="left arrow-icon flex-center">
                              <i class="fas fa-chevron-left"></i>
                            </span>
                            <span class="title flex-center">
                                <span class="post-nav-title-item">Java多线程之设计模式</span>
                                <span class="post-nav-item">上一篇</span>
                            </span>
                        </a>
                    </div>
                
                
                    <div class="article-next">
                        <a class="next"
                           rel="next"
                           href="/2019/02/27/bef97aa3/"
                        >
                            <span class="title flex-center">
                                <span class="post-nav-title-item">LeetCode链表</span>
                                <span class="post-nav-item">下一篇</span>
                            </span>
                            <span class="right arrow-icon flex-center">
                              <i class="fas fa-chevron-right"></i>
                            </span>
                        </a>
                    </div>
                
            </div>
        

        
            <div class="comment-container">
                <div class="comments-container">
    <div id="comment-anchor"></div>
    <div class="comment-area-title">
        <i class="fas fa-comments">&nbsp;评论</i>
    </div>
    

        
            <section class="disqus-comments">
<div id="disqus_thread">
  <noscript>Please enable JavaScript to view the <a target="_blank" rel="noopener" href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</section>

<script>
var disqus_shortname = 'imlgw';

var disqus_url = 'https://imlgw.top/2019/04/07/32b13d92/';

(function(){
  var dsq = document.createElement('script');
  dsq.type = 'text/javascript';
  dsq.async = true;
  dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>

<script id="dsq-count-scr" src="//imlgw.disqus.com/count.js" async></script>
        
    
</div>

            </div>
        
    </div>
</div>


                
            </div>

        </div>

        <div class="page-main-content-bottom">
            <footer class="footer">
    <div class="info-container">
        <div class="copyright-info info-item">
            &copy;
            
              <span>2018</span>&nbsp;-&nbsp;
            
            2021&nbsp;<i class="fas fa-heart icon-animate"></i>&nbsp;<a href="/">Resolmi</a>
        </div>
        
            <script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="website-count info-item">
                
                    <span id="busuanzi_container_site_uv">
                        访问人数&nbsp;<span id="busuanzi_value_site_uv"></span>&ensp;
                    </span>
                
                
                    <span id="busuanzi_container_site_pv">
                        总访问量&nbsp;<span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        
            <div class="icp-info info-item"><a target="_blank" rel="nofollow" href="https://beian.miit.gov.cn">鄂ICP备18011208号</a></div>
        
    </div>
</footer>

        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="tools-list">
        <!-- TOC aside toggle -->
        
            <li class="tools-item page-aside-toggle">
                <i class="fas fa-outdent"></i>
            </li>
        

        <!-- go comment -->
        
            <li class="go-comment">
                <i class="fas fa-comment"></i>
            </li>
        
    </ul>
</div>

        </div>
    

    <div class="right-bottom-side-tools">
        <div class="side-tools-container">
    <ul class="side-tools-list">
        <li class="tools-item tool-font-adjust-plus flex-center">
            <i class="fas fa-search-plus"></i>
        </li>

        <li class="tools-item tool-font-adjust-minus flex-center">
            <i class="fas fa-search-minus"></i>
        </li>

        <li class="tools-item tool-expand-width flex-center">
            <i class="fas fa-arrows-alt-h"></i>
        </li>

        <li class="tools-item tool-dark-light-toggle flex-center">
            <i class="fas fa-moon"></i>
        </li>

        <!-- rss -->
        

        

        <li class="tools-item tool-scroll-to-bottom flex-center">
            <i class="fas fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="exposed-tools-list">
        <li class="tools-item tool-toggle-show flex-center">
            <i class="fas fa-cog fa-spin"></i>
        </li>
        
            <li class="tools-item tool-scroll-to-top flex-center">
                <i class="arrow-up fas fa-arrow-up"></i>
                <span class="percent"></span>
            </li>
        
    </ul>
</div>

    </div>

    
        <aside class="page-aside">
            <div class="post-toc-wrap">
    <div class="post-toc">
        <ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E7%BA%BF%E7%A8%8B%E4%B8%8E%E8%BF%9B%E7%A8%8B%E5%8C%BA%E5%88%AB"><span class="nav-number">1.</span> <span class="nav-text">1.线程与进程区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%EF%BC%9F%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9F"><span class="nav-number">2.</span> <span class="nav-text">2.为什么要使用多线程？多线程应用场景？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA%E6%96%B9%E5%BC%8F"><span class="nav-number">3.</span> <span class="nav-text">3.线程创建方式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BFThread%E7%B1%BB%E9%87%8D%E5%86%99run%E6%96%B9%E6%B3%95"><span class="nav-number">3.1.</span> <span class="nav-text">继承Thread类重写run方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0Runnable%E6%8E%A5%E5%8F%A3"><span class="nav-number">3.2.</span> <span class="nav-text">实现Runnable接口</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB"><span class="nav-number">3.3.</span> <span class="nav-text">匿名内部类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Thread-%E7%B1%BB%E4%B8%AD%E7%9A%84start-%E5%92%8C-run-%E6%96%B9%E6%B3%95%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%EF%BC%9F"><span class="nav-number">3.4.</span> <span class="nav-text">Thread 类中的start() 和 run() 方法有什么区别？</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-Thread%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="nav-number">4.</span> <span class="nav-text">4.Thread构造函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Thread%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E7%9A%84%E4%B8%80%E4%BA%9B%E7%BB%86%E8%8A%82"><span class="nav-number">4.1.</span> <span class="nav-text">Thread构造方法的一些细节</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B"><span class="nav-number">5.</span> <span class="nav-text">5.守护线程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="nav-number">5.1.</span> <span class="nav-text">应用场景</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-%E7%BA%BF%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81"><span class="nav-number">6.</span> <span class="nav-text">6.线程的状态</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-join-%E6%96%B9%E6%B3%95"><span class="nav-number">7.</span> <span class="nav-text">7.join()方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90"><span class="nav-number">7.1.</span> <span class="nav-text">源码解析</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF-1"><span class="nav-number">7.2.</span> <span class="nav-text">应用场景</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#8-%E4%BC%98%E5%85%88%E7%BA%A7"><span class="nav-number">8.</span> <span class="nav-text">8.优先级</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#9-Interrupt%E6%96%B9%E6%B3%95"><span class="nav-number">9.</span> <span class="nav-text">9.Interrupt方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%9C%8B%E7%9C%8B%E6%BA%90%E7%A0%81"><span class="nav-number">9.1.</span> <span class="nav-text">看看源码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E7%BB%93%E6%9D%9F%E7%BA%BF%E7%A8%8B"><span class="nav-number">9.2.</span> <span class="nav-text">如何优雅的结束线程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Thread-interrupted"><span class="nav-number">9.3.</span> <span class="nav-text">Thread.interrupted()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-Yield%E6%96%B9%E6%B3%95"><span class="nav-number">10.</span> <span class="nav-text">10.Yield方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-Synchronized%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-number">11.</span> <span class="nav-text">11.Synchronized关键字</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98"><span class="nav-number">11.1.</span> <span class="nav-text">线程安全问题</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%90%8C%E6%AD%A5%E4%BB%A3%E7%A0%81%E5%9D%97"><span class="nav-number">11.2.</span> <span class="nav-text">同步代码块</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%90%8C%E6%AD%A5%E6%96%B9%E6%B3%95"><span class="nav-number">11.3.</span> <span class="nav-text">同步方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%AD%BB%E9%94%81"><span class="nav-number">11.4.</span> <span class="nav-text">死锁</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E7%BA%BF%E7%A8%8B%E9%97%B4%E9%80%9A%E8%AE%AF"><span class="nav-number">12.</span> <span class="nav-text">12.线程间通讯</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%9E%8B"><span class="nav-number">12.1.</span> <span class="nav-text">生产者消费者模型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88wait%E5%92%8Cnotify%E5%BF%85%E9%A1%BB%E5%9C%A8%E5%90%8C%E6%AD%A5%E6%96%B9%E6%B3%95%E6%88%96%E5%90%8C%E6%AD%A5%E5%9D%97%E4%B8%AD%E8%B0%83%E7%94%A8%EF%BC%9F"><span class="nav-number">12.2.</span> <span class="nav-text">为什么wait和notify必须在同步方法或同步块中调用？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#wait-%E5%90%8E%E8%A2%AB%E5%94%A4%E9%86%92%E4%BC%9A%E6%80%8E%E4%B9%88%E6%A0%B7%EF%BC%9F"><span class="nav-number">12.3.</span> <span class="nav-text">wait()后被唤醒会怎么样？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#notify%E5%92%8C%E4%B8%AD%E6%96%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E5%BE%88%E6%9C%89%E6%84%8F%E6%80%9D%E7%9A%84%E7%8E%B0%E8%B1%A1"><span class="nav-number">12.4.</span> <span class="nav-text">notify和中断的一个很有意思的现象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#wait-%E5%92%8Csleep-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">12.5.</span> <span class="nav-text">wait()和sleep()的区别</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E9%80%9A%E8%AE%AF%E7%BB%BC%E5%90%88%E6%A1%88%E4%BE%8B"><span class="nav-number">12.6.</span> <span class="nav-text">线程通讯综合案例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#wait-notify%E7%9A%84%E5%BC%80%E9%94%80%E5%8F%8A%E9%97%AE%E9%A2%98"><span class="nav-number">12.7.</span> <span class="nav-text">wait()&#x2F;notify的开销及问题</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-%E6%89%8B%E5%86%99%E4%B8%80%E4%B8%AABooleanLock"><span class="nav-number">13.</span> <span class="nav-text">13.手写一个BooleanLock</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#LOCK%E6%8E%A5%E5%8F%A3"><span class="nav-number">13.1.</span> <span class="nav-text">LOCK接口</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#BooleanLock%E5%AE%9E%E7%8E%B0%E7%B1%BB"><span class="nav-number">13.2.</span> <span class="nav-text">BooleanLock实现类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%B5%8B%E8%AF%95BooleanLock%E7%9A%84%E6%95%88%E6%9E%9C"><span class="nav-number">13.3.</span> <span class="nav-text">测试BooleanLock的效果</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-%E7%BB%99%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%B3%A8%E5%85%A5%E9%92%A9%E5%AD%90Hook"><span class="nav-number">14.</span> <span class="nav-text">14.给应用程序注入钩子Hook</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-%E6%8D%95%E8%8E%B7%E7%BA%BF%E7%A8%8B%E7%9A%84Runtime%E5%BC%82%E5%B8%B8"><span class="nav-number">15.</span> <span class="nav-text">15.捕获线程的Runtime异常</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-ThreadGroup%E7%BA%BF%E7%A8%8B%E7%BB%84"><span class="nav-number">16.</span> <span class="nav-text">16.ThreadGroup线程组</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%8E%B7%E5%8F%96%E7%BA%BF%E7%A8%8B%E7%BB%84%E4%BF%A1%E6%81%AF"><span class="nav-number">16.1.</span> <span class="nav-text">获取线程组信息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%89%93%E6%96%AD%E7%BA%BF%E7%A8%8B%E7%BB%84interrupt"><span class="nav-number">16.2.</span> <span class="nav-text">打断线程组interrupt()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E7%BB%84setDaemon"><span class="nav-number">16.3.</span> <span class="nav-text">线程组setDaemon()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="nav-number">17.</span> <span class="nav-text">17.线程池</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BD%BF%E7%94%A8%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="nav-number">17.1.</span> <span class="nav-text">为什么要使用线程池</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%89%8B%E5%86%99%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="nav-number">17.2.</span> <span class="nav-text">手写线程池</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%B8%B4%E6%97%B6%E9%98%9F%E5%88%97"><span class="nav-number">17.2.1.</span> <span class="nav-text">临时队列</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%85%B3%E9%97%AD%E7%BA%BF%E7%A8%8B%E6%B1%A0-amp-%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5"><span class="nav-number">17.2.2.</span> <span class="nav-text">关闭线程池&amp;拒绝策略</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%87%AA%E5%8A%A8%E6%89%A9%E5%AE%B9-amp-%E9%97%B2%E6%97%B6%E5%9B%9E%E6%94%B6"><span class="nav-number">17.2.3.</span> <span class="nav-text">自动扩容&amp;闲时回收</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%B5%8B%E8%AF%95%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="nav-number">17.3.</span> <span class="nav-text">测试线程池</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"><span class="nav-number">18.</span> <span class="nav-text">参考资料</span></a></li></ol>
    </div>
</div>
        </aside>
    

    <div class="image-viewer-container">
    <img src="">
</div>


    
        <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
          <span class="search-input-field-pre">
            <i class="fas fa-keyboard"></i>
          </span>
            <div class="search-input-container">
                <input autocomplete="off"
                       autocorrect="off"
                       autocapitalize="off"
                       placeholder="搜索..."
                       spellcheck="false"
                       type="search"
                       class="search-input"
                >
            </div>
            <span class="popup-btn-close">
                <i class="fas fa-times"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fas fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>

    

</main>



<script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/utils.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/main.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/header-shrink.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/back2top.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/dark-light-toggle.js"></script>


    <script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/local-search.js"></script>



    <script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/code-copy.js"></script>



    <script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/lazyload.js"></script>


<div class="post-scripts pjax">
    
        <script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/left-side-toggle.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/libs/anime.min.js"></script><script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/toc.js"></script>
    
</div>


    <script src="//cdn.jsdelivr.net/npm/hexo-theme-keep@3.4.3/source/js/libs/pjax.min.js"></script>
<script>
    window.addEventListener('DOMContentLoaded', () => {
        window.pjax = new Pjax({
            selectors: [
                'head title',
                '.page-container',
                '.pjax'
            ],
            history: true,
            debug: false,
            cacheBust: false,
            timeout: 0,
            analytics: false,
            currentUrlFullReload: false,
            scrollRestoration: false,
            // scrollTo: true,
        });

        document.addEventListener('pjax:send', () => {
            KEEP.utils.pjaxProgressBarStart();
        });

        document.addEventListener('pjax:complete', () => {
            KEEP.utils.pjaxProgressBarEnd();
            window.pjax.executeScripts(document.querySelectorAll('script[data-pjax], .pjax script'));
            KEEP.refresh();
        });
    });
</script>



<script src="https://cdn.jsdelivr.net/npm/live2d-widget@3.x/lib/L2Dwidget.min.js"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"https://cdn.jsdelivr.net/npm/live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json"},"display":{"superSample":2,"width":160,"height":320,"position":"right","hOffset":0,"vOffset":-70},"mobile":{"show":false,"scale":0.2},"log":false});</script></body>
</html>
